public record GenericArgumentResult(Type RequestedType, Type DirectSubclass, Type[] GenericArguments); public static class GenericTypeHelper { /// /// Returns of , /// even from : . /// /// For e.g EntityTypeBuilderOfEntity. /// for e.g typeof(). /// An enumerable of generic arguments of . public static IEnumerable GetGenericArgumentsOfTypeDefinition( Type concreteType, Type genericDefinition ) { return EnumerateBaseTypesAndInterfaces(concreteType) .Where(x => x.IsGenericType) .Where(x => x.GetGenericTypeDefinition() == genericDefinition) .Select(x => new GenericArgumentResult( RequestedType: concreteType, DirectSubclass: x, GenericArguments: x.GenericTypeArguments )); } // same as GetGenericArgumentsOfTypeDefinition but returns only the first result public static GenericArgumentResult? GetFirstGenericArgumentsOfTypeDefinition( Type concreteType, Type genericDefinition, Func? predicate = null ) { var result = GetGenericArgumentsOfTypeDefinition(concreteType, genericDefinition); if (predicate != null) { result = result.Where(predicate); } return result.FirstOrDefault(); } private static IEnumerable EnumerateBaseTypesAndInterfaces(Type? type, bool returnInput = true) { if (type == null) { yield break; } if (returnInput) { yield return type; } // Return all base types var current = type.BaseType; while (current != null) { foreach (var interfaceType in current.GetInterfaces()) { yield return interfaceType; } yield return current; current = current.BaseType; } // Return all interfaces foreach (var interfaceType in type.GetInterfaces()) { yield return interfaceType; } } }