dotnet/efcore · error · InvalidOperationException

Unknown generic type parameter symbol

Error message

Unknown generic type parameter symbol {typeParameterSymbol}

What it means

Thrown by CSharpToLinqTranslator.ResolveType(ITypeSymbol, genericParameterMap) when the symbol is an ITypeParameterSymbol (e.g. 'T') whose Name is not present in the supplied genericParameterMap. The translator only resolves generic type parameters that have been bound into the map; an unbound type parameter cannot be turned into a concrete CLR Type.

Solutions

  1. Close the generic at the call site so the type argument is concrete (e.g. call MyHelper<User> rather than MyHelper<T> at the top level).
  2. Avoid referencing open generic type parameters in expression-tree-constructible positions inside EF query lambdas.
  3. If hosting the translator, ensure ResolveType is entered with a genericParameterMap that contains the outer type's type arguments before recursing into T-bearing expressions.

Example fix

// before (T flows into an expression the translator must resolve)
public IQueryable<T> Active<T>(IQueryable<T> q) => q.Where(x => ((T)x).Id != 0);

// after (close the generic so T is concrete at each call site)
public IQueryable<User> Active(IQueryable<User> q) => q.Where(x => x.Id != 0);
Defensive patterns

Strategy: validation

Validate before calling

// Check that no open generic type parameter leaks into the expression you translate.
using System.Linq.Expressions;

bool ContainsOpenGenericParameter(Expression e)
{
    bool found = false;
    new OpenGenericFinder(t =>
    {
        if (t.IsGenericParameter) found = true;
    }).Visit(e);
    return found;
}

class OpenGenericFinder(Action<Type> onType) : ExpressionVisitor
{
    protected override Expression VisitConstant(ConstantExpression c)
    {
        if (c.Value is Type t) onType(t);
        return base.VisitConstant(c);
    }
    // Extend with member/type visitation as needed.
}

Prevention

When it happens

Trigger: Translating an expression that references a generic type parameter T which is not part of an open generic context tracked via genericParameterMap — e.g. a method that consumes a generic argument defined on an outer type that was never added to the map, or an open-generic type used as an array element / nested reference.

Common situations: Using open generics inside EF queries that the precompiled-query translator has not been taught to bind; building a generic query helper that flows T into an expression which is then handed to the translator without supplying a genericParameterMap.

Related errors


AI-assisted analysis of dotnet/efcore@3a2006ef56 (2026-08-11). Data as JSON: /api/errors/ea4837b45808fabd. Report an issue: GitHub.

Appendix: source

Thrown at src/EFCore.Design/Query/Internal/CSharpToLinqTranslator.cs:1160

                // TODO: Cache closed anonymous types

                return anonymousTypeGenericDefinition.MakeGenericType(genericTypeArguments);

            case INamedTypeSymbol { IsDefinition: true } genericTypeSymbol:
                return GetClrType(genericTypeSymbol);

            case INamedTypeSymbol { IsGenericType: true } genericTypeSymbol:
            {
                var definition = GetClrType(genericTypeSymbol.OriginalDefinition);
                var typeArguments = genericTypeSymbol.TypeArguments.Select(a => ResolveType(a, genericParameterMap)).ToArray();
                return definition.MakeGenericType(typeArguments);
            }

            case ITypeParameterSymbol typeParameterSymbol:
                return genericParameterMap?.TryGetValue(typeParameterSymbol.Name, out var type) == true
                    ? type
                    : throw new InvalidOperationException($"Unknown generic type parameter symbol {typeParameterSymbol}");

            case INamedTypeSymbol namedTypeSymbol:
                return GetClrType(namedTypeSymbol);

            case IArrayTypeSymbol arrayTypeSymbol:
                // The ContainingAssembly of array type symbols can be null; recurse down the element types (down to the non-array element
                // type) to get the assembly.
                var containingAssembly = arrayTypeSymbol.ContainingAssembly;
                ITypeSymbol currentSymbol = arrayTypeSymbol;
                while (containingAssembly is null && currentSymbol is IArrayTypeSymbol { ElementType: var nestedTypeSymbol })
                {
                    currentSymbol = nestedTypeSymbol;
                    containingAssembly = currentSymbol.ContainingAssembly;
                }

                return GetClrTypeFromAssembly(
                    containingAssembly,
                    typeSymbol.ToDisplayString(QualifiedTypeNameSymbolDisplayFormat));

View on GitHub (pinned to 3a2006ef56)