dotnet/efcore · error · InvalidOperationException

Cannot translate the

Error message

Cannot translate the '{comparisonOperator}' on an expression of entity type '{entityType}' because it is a keyless entity. Consider using entity properties instead. For more information on keyless entity types, see https://go.microsoft.com/fwlink/?linkid=2141943.

What it means

When translating Queryable.Contains on an entity, StructuralEquality needs the entity's single primary key property to build an IN clause. If FindPrimaryKey returns null (keyless entity) it throws InvalidOperationException CoreStrings.EntityEqualityOnKeylessEntityNotSupported — Contains cannot be expressed without a key.

Solutions

  1. Compare on a concrete property instead of the entity: .Where(x => ids.Contains(x.SomeId)).
  2. Configure a key on the entity if equality semantics are genuinely needed.
  3. Materialize the keyless sequence client-side and filter there.

Example fix

// before
var q = db.Views.Where(v => allowed.Contains(v));
// after
var q = db.Views.Where(v => allowedIds.Contains(v.Code));
Defensive patterns

Strategy: validation

Validate before calling

// compare on scalar keys, not on the entity
static IQueryable<T> InByKey<T>(IQueryable<T> q, IEnumerable<string> keys, string propName)
    where T : class
    => q.Where(x => keys.Contains(EF.Property<string>(x, propName)));

Type guard

static bool EntityHasKey<T>(DbContext ctx)
    => ctx.Model.FindEntityType(typeof(T))?.FindPrimaryKey() is not null;

Prevention

When it happens

Trigger: Calling .Contains(entity) or building an IN-style filter where the element type is a keyless entity (HasNoKey configured).

Common situations: Modeling a view/report type as keyless and then attempting Contains/Any-equality filters against it, or accidentally removing a key configuration.

Related errors


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

Appendix: source

Thrown at src/EFCore.Cosmos/Query/Internal/CosmosSqlTranslatingExpressionVisitor.StructuralEquality.cs:37

    private static readonly MethodInfo ParameterListValueExtractorMethod =
        typeof(CosmosSqlTranslatingExpressionVisitor).GetTypeInfo().GetDeclaredMethod(nameof(ParameterListValueExtractor))!;

    private bool TryRewriteContainsEntity(Expression source, Expression item, [NotNullWhen(true)] out Expression? result)
    {
        result = null;

        if (item is not StructuralTypeReferenceExpression { StructuralType: IEntityType entityType })
        {
            return false;
        }

        var primaryKeyProperties = entityType.FindPrimaryKey()?.Properties;

        switch (primaryKeyProperties)
        {
            case null:
                throw new InvalidOperationException(
                    CoreStrings.EntityEqualityOnKeylessEntityNotSupported(
                        nameof(Queryable.Contains), entityType.DisplayName()));

            case { Count: > 1 }:
                throw new InvalidOperationException(
                    CoreStrings.EntityEqualityOnCompositeKeyEntitySubqueryNotSupported(
                        nameof(Queryable.Contains), entityType.DisplayName()));
        }

        var property = primaryKeyProperties[0];
        Expression rewrittenSource;
        switch (source)
        {
            case SqlConstantExpression sqlConstantExpression:
                var values = (IEnumerable)sqlConstantExpression.Value!;
                var propertyValueList =
                    (IList)Activator.CreateInstance(typeof(List<>).MakeGenericType(property.ClrType.MakeNullable()))!;
                var propertyGetter = property.GetGetter();

View on GitHub (pinned to 3a2006ef56)