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
- 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).
- Avoid referencing open generic type parameters in expression-tree-constructible positions inside EF query lambdas.
- 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
- Close generics at the public call site so the translator never sees unbound T.
- Avoid embedding typeof(T) where T is an unbound method/outer-class type parameter into EF query expressions.
- When hosting the translator, supply a genericParameterMap that binds every outer type argument before recursion.
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
- Could not find type symbol for
- Couldn't find nested type
- Could not found symbol for parameter lambda
- Couldn't resolve CLR type
- Lambda with modifiers not supported
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)