docs: private <IN1, IN2> TypeInformation<?>[] createSubTypesInfo(Type originalType, ParameterizedType definingType,
  			ArrayList<Type> typeHierarchy, TypeInformation<IN1> in1Type, TypeInformation<IN2> in2Type, boolean lenient) {
  		Type[] subtypes = new Type[definingType.getActualTypeArguments().length];
  
  		// materialize possible type variables
  		for (int i = 0; i < subtypes.length; i++) {
  			final Type actualTypeArg = definingType.getActualTypeArguments()[i];
  			// materialize immediate TypeVariables
  			if (actualTypeArg instanceof TypeVariable<?>) {
  				subtypes[i] = materializeTypeVariable(typeHierarchy, (TypeVariable<?>) actualTypeArg);
  			}
  			// class or parameterized type
  			else {
  				subtypes[i] = actualTypeArg;
  			}
  		}
  
  		TypeInformation<?>[] subTypesInfo = new TypeInformation<?>[subtypes.length];
  		for (int i = 0; i < subtypes.length; i++) {
  			final ArrayList<Type> subTypeHierarchy = new ArrayList<>(typeHierarchy);
  			subTypeHierarchy.add(subtypes[i]);
  			// sub type could not be determined with materializing
  			// try to derive the type info of the TypeVariable from the immediate base child input as a last attempt
  			if (subtypes[i] instanceof TypeVariable<?>) {
  				subTypesInfo[i] = createTypeInfoFromInputs((TypeVariable<?>) subtypes[i], subTypeHierarchy, in1Type, in2Type);
  
  				// variable could not be determined
  				if (subTypesInfo[i] == null && !lenient) {
  					throw new InvalidTypesException("Type of TypeVariable '" + ((TypeVariable<?>) subtypes[i]).getName() + "' in '"
  						+ ((TypeVariable<?>) subtypes[i]).getGenericDeclaration()
  						+ "' could not be determined. This is most likely a type erasure problem. "
  						+ "The type extraction currently supports types with generic variables only in cases where "
  						+ "all variables in the return type can be deduced from the input type(s). "
  						+ "Otherwise the type has to be specified explicitly using type information.");
  				}
  			} else {
  				// create the type information of the subtype or null/exception
  				try {
  					subTypesInfo[i] = createTypeInfoWithTypeHierarchy(subTypeHierarchy, subtypes[i], in1Type, in2Type);
  				} catch (InvalidTypesException e) {
  					if (lenient) {
  						subTypesInfo[i] = null;
  					} else {
  						throw e;
  					}
  				}
  			}
  		}
  
  		// check that number of fields matches the number of subtypes
  		if (!lenient) {
  			Class<?> originalTypeAsClass = null;
  			if (isClassType(originalType)) {
  				originalTypeAsClass = typeToClass(originalType);
  			}
  			checkNotNull(originalTypeAsClass, "originalType has an unexpected type");
  			// check if the class we assumed to conform to the defining type so far is actually a pojo because the
  			// original type contains additional fields.
  			// check for additional fields.
  			int fieldCount = countFieldsInClass(originalTypeAsClass);
  			if(fieldCount > subTypesInfo.length) {
  				return null;
  			}
  		}
  
  		return subTypesInfo;
  	}