dotnet/efcore · error · InvalidOperationException

The operation '{operation}' is being applied on entity type

Error message

The operation '{operation}' is being applied on entity type '{entityType}', which uses entity splitting. 'ExecuteDelete'/'ExecuteUpdate' operations on entity types using entity splitting are not supported.

What it means

TranslateExecuteDelete requires exactly one table mapping; the default arm of the switch throws when entityType.GetTableMappings() returns more than one mapping, i.e. the entity is split across multiple tables (entity splitting via multiple .ToTable calls mapping different properties). A single parametrized DELETE cannot update all split tables atomically, so ExecuteDelete/ExecuteUpdate are refused.

Source

Thrown at src/EFCore.Relational/Query/RelationalQueryableMethodTranslatingExpressionVisitor.ExecuteDelete.cs:48

                    RelationalStrings.ExecuteOperationOnTPT(
                        nameof(EntityFrameworkQueryableExtensions.ExecuteDelete),
                        entityType.DisplayName()));

            // Note that we do allow TPC if the target is a leaf type
            case RelationalAnnotationNames.TpcMappingStrategy when entityType.GetDirectlyDerivedTypes().Any():
                throw new InvalidOperationException(
                    RelationalStrings.ExecuteOperationOnTPC(
                        nameof(EntityFrameworkQueryableExtensions.ExecuteDelete),
                        entityType.DisplayName()));
        }

        // Find the table model that maps to the entity type; there must be exactly one (e.g. no entity splitting).
        var targetTable = entityType.GetTableMappings().ToList() switch
        {
            [] => throw new InvalidOperationException(
                RelationalStrings.ExecuteUpdateDeleteOnEntityNotMappedToTable(entityType.DisplayName())),
            [var singleTableMapping] => singleTableMapping.Table,
            _ => throw new InvalidOperationException(
                RelationalStrings.ExecuteOperationOnEntitySplitting(
                    nameof(EntityFrameworkQueryableExtensions.ExecuteDelete), entityType.DisplayName())),
        };
        var selectExpression = (SelectExpression)source.QueryExpression;

        // Find the table expression in the SelectExpression that corresponds to the projected entity type.
        var projectionBindingExpression = (ProjectionBindingExpression)shaper.ValueBufferExpression;
        var projection = (StructuralTypeProjectionExpression)selectExpression.GetProjection(projectionBindingExpression);
        var column = projection.BindProperty(shaper.StructuralType.GetProperties().First());
        var tableExpression = selectExpression.GetTable(column, out var tableIndex);

        // If the projected table expression (the thing to be deleted) isn't a TableExpression (e.g. it's a set operation), we can't
        // translate to a simple DELETE (which requires a simple target table), and must fall back to rewriting as a subquery.
        if (tableExpression.UnwrapJoin() is TableExpression unwrappedTableExpression)
        {
            // In normal cases, the table expression will be refer to the same table model we found above for the entity type.
            if (unwrappedTableExpression.Table is ITable)
            {

View on GitHub (pinned to 3a2006ef56)

Solutions

  1. Consolidate the entity into a single table mapping (remove the splitting ToTable calls).
  2. Load entities and use RemoveRange + SaveChanges so EF deletes from each split table correctly.
  3. Issue raw SQL DELETEs against each split table in the correct order.

Example fix

// before (entity splitting -> 595)
modelBuilder.Entity<Customer>()
    .ToTable("customers")
    .SplitToTable("customer_details", t => t.Property(c => c.Notes));
await db.Customers.Where(c => c.Archived).ExecuteDeleteAsync();
// after (single table, or use SaveChanges)
await db.Customers.Where(c => c.Archived).ExecuteDeleteAsync(); // after removing SplitToTable
Defensive patterns

Strategy: validation

Validate before calling

// Refuse ExecuteDelete/ExecuteUpdate on entities with multiple table mappings (splitting).
var et = db.Model.FindEntityType(typeof(TEntity))!;
var tableCount = et.GetTableMappings().Select(m => m.Table).Distinct().Count();
if (tableCount > 1)
    throw new InvalidOperationException(
        $"{et.Name} uses entity splitting ({tableCount} tables); bulk delete/update is unsupported. Use SaveChanges or raw SQL.");

Prevention

When it happens

Trigger: ExecuteDelete/ExecuteUpdate on an entity configured with entity splitting, e.g. modelBuilder.Entity<T>().ToTable("t_main") and a second ToTable mapping a subset of properties to "t_extra"; executing the bulk operation triggers the multi-mapping arm.

Common situations: Legacy models using entity splitting for column count limits; refactoring a wide table into a main + extension table and expecting existing ExecuteDelete calls to keep working.

Related errors


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