dotnet/efcore · error · InvalidOperationException

The operation 'ExecuteDelete' is being applied on the table

Error message

The operation 'ExecuteDelete' is being applied on the table '{tableName}' which contains data for multiple entity types. Applying this delete operation will also delete data for other entity type(s), hence it is not supported.

What it means

After IsValidSelectExpressionForExecuteDelete succeeds, TranslateExecuteDelete verifies the target table does not store rows for any other non-owned entity type (AreOtherNonOwnedEntityTypesInTheTable). If the table is shared (table splitting between multiple principal entity types), a single DELETE would corrupt the other type's data, so EF refuses.

Source

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

                tableExpression = tableExpression is JoinExpressionBase join
                    ? join.Update(unwrappedTableExpression)
                    : unwrappedTableExpression;
                var newTables = selectExpression.Tables.ToList();
                newTables[tableIndex] = tableExpression;

                // Note that we need to keep the select mutable, because if IsValidSelectExpressionForExecuteDelete below returns false,
                // we need to compose on top of it.
                selectExpression.SetTables(newTables);
            }

            // Finally, check if the provider has a native translation for the delete represented by the select expression.
            // The default relational implementation handles simple, universally-supported cases (i.e. no operators except for predicate).
            // Providers may override IsValidSelectExpressionForExecuteDelete to add support for more cases via provider-specific DELETE syntax.
            if (IsValidSelectExpressionForExecuteDelete(selectExpression))
            {
                if (AreOtherNonOwnedEntityTypesInTheTable(entityType.GetRootType(), targetTable))
                {
                    throw new InvalidOperationException(
                        RelationalStrings.ExecuteDeleteOnTableSplitting(unwrappedTableExpression.Table.SchemaQualifiedName));
                }

                selectExpression.ReplaceProjection([]);
                selectExpression.ApplyProjection();

                return new DeleteExpression(unwrappedTableExpression, selectExpression);
            }
        }

        // We can't translate to a simple delete (e.g. the provider doesn't support one of the clauses).
        // As a fallback, we place the original query in a Contains subquery, which will get translated via the regular entity equality/
        // containment mechanism (InExpression for non-composite keys, Any for composite keys)
        var pk = entityType.FindPrimaryKey();
        if (pk == null)
        {
            throw new InvalidOperationException(
                RelationalStrings.ExecuteOperationOnKeylessEntityTypeWithUnsupportedOperator(

View on GitHub (pinned to 3a2006ef56)

Solutions

  1. Map each entity type to its own table so deletes are not ambiguous.
  2. Load entities and use RemoveRange + SaveChanges, which understands shared-table mappings and updates only the relevant columns (or use raw SQL constrained by the entity's key).
  3. Restructure the shared table: make one entity the owner and the others owned types so EF coordinates writes.

Example fix

// before (two entities share 'orders' table -> 596)
modelBuilder.Entity<Order>().ToTable("orders");
modelBuilder.Entity<OrderAudit>().ToTable("orders");
await db.Orders.Where(o => o.Closed).ExecuteDeleteAsync();
// after (separate tables, or use SaveChanges)
modelBuilder.Entity<OrderAudit>().ToTable("order_audits");
await db.Orders.Where(o => o.Closed).ExecuteDeleteAsync();
Defensive patterns

Strategy: validation

Validate before calling

// Detect shared tables (multiple non-owned entity types on the same table) before ExecuteDelete.
var et = db.Model.FindEntityType(typeof(TEntity))!;
var root = et.GetRootType();
foreach (var mapping in root.GetTableMappings())
{
    var others = mapping.Table.EntityTypeMappings
        .Where(m => !m.EntityType.IsInOwnershipPath() && m.EntityType != root)
        .Select(m => m.EntityType.Name);
    if (others.Any())
        throw new InvalidOperationException(
            $"Table {mapping.Table.Name} is shared with {string.Join(", ", others)}; ExecuteDelete is ambiguous.");
}

Prevention

When it happens

Trigger: Two or more entity types mapped to the same table (shared table, distinct keys/columns), and ExecuteDelete targeting one of them would delete rows that also belong to the others. Common with table splitting configurations (entity A and entity B both ToTable("shared")).

Common situations: Table-splitting (multiple entities sharing a row to work around column limits or to model optional sections); owning entity and a sibling entity mapped to the same table; refactoring a table into multiple entities without changing the physical table.

Related errors


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