dotnet/efcore · error · InvalidOperationException

QueryRootDifferentEntityType

QueryRootDifferentEntityType

Error message

The replacement entity type: {entityType} does not have same name and CLR type as entity type this query root represents.

What it means

Thrown by TableValuedFunctionQueryRootExpression.UpdateEntityType (TableValuedFunctionQueryRootExpression.cs:78) when the replacement entity type differs from the query root's entity type in either CLR type or name. A table-valued-function query root is bound to a specific entity type; replacing it with an incompatible one would desync the TVF mapping from the shaper, so EF refuses.

Source

Thrown at src/EFCore.Relational/Query/Internal/TableValuedFunctionQueryRootExpression.cs:78

            arguments.Add(newArgument);
            changed |= argument != newArgument;
        }

        return changed
            ? new TableValuedFunctionQueryRootExpression(EntityType, Function, arguments)
            : this;
    }

    /// <summary>
    ///     This is an internal API that supports the Entity Framework Core infrastructure and not subject to
    ///     the same compatibility standards as public APIs. It may be changed or removed without notice in
    ///     any release. You should only use it directly in your code with extreme caution and knowing that
    ///     doing so can result in application failures when updating to a new Entity Framework Core release.
    /// </summary>
    public override EntityQueryRootExpression UpdateEntityType(IEntityType entityType)
        => entityType.ClrType != EntityType.ClrType
            || entityType.Name != EntityType.Name
                ? throw new InvalidOperationException(CoreStrings.QueryRootDifferentEntityType(entityType.DisplayName()))
                : new TableValuedFunctionQueryRootExpression(entityType, Function, Arguments);

    /// <summary>
    ///     This is an internal API that supports the Entity Framework Core infrastructure and not subject to
    ///     the same compatibility standards as public APIs. It may be changed or removed without notice in
    ///     any release. You should only use it directly in your code with extreme caution and knowing that
    ///     doing so can result in application failures when updating to a new Entity Framework Core release.
    /// </summary>
    protected override void Print(ExpressionPrinter expressionPrinter)
    {
        expressionPrinter.Append(Function.Name);
        expressionPrinter.Append("(");
        expressionPrinter.VisitCollection(Arguments);
        expressionPrinter.Append(")");
    }

    /// <summary>
    ///     This is an internal API that supports the Entity Framework Core infrastructure and not subject to

View on GitHub (pinned to dbf9771522)

Solutions

  1. Ensure the entity type passed to UpdateEntityType has the same ClrType and Name as the original query root's EntityType.
  2. Recreate the query root for the new entity type instead of calling UpdateEntityType with a mismatched type.
  3. If rebinding to a derived type, build a new TableValuedFunctionQueryRootExpression for that type.
  4. Verify you are using entity types from the same IModel the query was compiled against.

Example fix

// before - rebinding a TVF query root to an incompatible entity type
var newRoot = tvfQueryRoot.UpdateEntityType(otherEntityType); // ClrType/Name differ -> throws

// after - ensure the replacement matches, or construct a fresh root for the target type
var matchingType = model.FindEntityType(originalEntityType.Name)!; // same name + CLR type
var newRoot = tvfQueryRoot.UpdateEntityType(matchingType);
// or: var fresh = new TableValuedFunctionQueryRootExpression(targetType, function, args);
Defensive patterns

Strategy: validation

Validate before calling

// Before UpdateEntityType, ensure name + CLR type match.
static bool IsCompatible(IEntityType original, IEntityType replacement)
    => original.ClrType == replacement.ClrType && original.Name == replacement.Name;
// Usage: if (!IsCompatible(root.EntityType, newType)) { /* build a fresh root */ }

Type guard

static bool EntityTypeMatches(IEntityType a, IEntityType b) => a.Name == b.Name && a.ClrType == b.ClrType;

Try / catch

try { var r = root.UpdateEntityType(newType); }
catch (InvalidOperationException ex) when (ex.Message.Contains("does not have same name and CLR type")) {
    // Replacement entity type is incompatible; construct a new query root instead.
    var fresh = new TableValuedFunctionQueryRootExpression(newType, function, args);
}

Prevention

When it happens

Trigger: Calling UpdateEntityType on a TableValuedFunctionQueryRootExpression with an IEntityType whose ClrType or Name differs from the original. Encountered by EF internals (e.g. model conformance / replacing query roots during precompilation) or by advanced code that manipulates query trees / implements a custom IQueryTranslationPreprocessor.

Common situations: Custom query-root rewriting that swaps entity types; using an entity type from a different model instance; TPT/TPC or entity-splitting scenarios where a TVF query root is rebound to a derived/different type; bugs in providers/extensions that call UpdateEntityType with mismatched types.

Related errors


AI-assisted analysis of dotnet/efcore@dbf9771522 (2026-08-06). Data as JSON: /api/errors/bb62095bd2de6054. Report an issue: GitHub.