dotnet/efcore · error · InvalidOperationException
'ExecuteUpdate' or 'ExecuteDelete' was called on entity type
Error message
'ExecuteUpdate' or 'ExecuteDelete' was called on entity type '{entityType}', but that entity type is not mapped to a table. What it means
TranslateExecuteDelete resolves targetTable from entityType.GetTableMappings(); the empty-list arm throws when the entity type has no table mappings at all. Without a backing table there is nothing to DELETE from, so ExecuteDelete/ExecuteUpdate cannot be translated.
Source
Thrown at src/EFCore.Relational/Query/RelationalQueryableMethodTranslatingExpressionVisitor.ExecuteDelete.cs:45
{
case RelationalAnnotationNames.TptMappingStrategy:
throw new InvalidOperationException(
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)
{View on GitHub (pinned to 3a2006ef56)
Solutions
- Map the entity to a table: modelBuilder.Entity<T>().ToTable("t").
- If the type is genuinely view-backed/read-only, do not call ExecuteDelete on it; perform deletes on the writable owner or via raw SQL.
- Verify the entity has a primary key and is not excluded from the model (IsIgnored/HasNoKey).
Example fix
// before (view-backed, no table mapping)
await db.Set<ReadOnlyView>().Where(x => x.Old).ExecuteDeleteAsync();
// after (map to a table, or delete via raw SQL)
modelBuilder.Entity<ReadOnlyView>().ToTable("readonly_table");
await db.Database.ExecuteSqlRawAsync("DELETE FROM readonly_table WHERE old = 1"); Defensive patterns
Strategy: validation
Validate before calling
// Ensure the entity is mapped to at least one table before ExecuteDelete/ExecuteUpdate.
var et = db.Model.FindEntityType(typeof(TEntity))!;
if (!et.GetTableMappings().Any())
throw new InvalidOperationException(
$"{et.Name} is not mapped to a table; configure ToTable or delete via raw SQL."); Prevention
- Map every entity that supports bulk delete to a real table (not just ToView).
- Audit HasNoKey/ToView-only types before adding ExecuteDelete calls.
- Keep an integration test that asserts each bulk-delete target has a table mapping.
When it happens
Trigger: context.Set<KeylessView>().ExecuteDelete() where the type is mapped ToView (not a table) or not mapped at all; ExecuteDelete on a query-only / projection-only entity; an entity type that was never configured with ToTable and is not table-mapped by convention.
Common situations: Read-only view-backed entities; keyless types; entities used only for results of FromSql/SQL; misconfigured model where ToTable was removed or never set.
Related errors
- The operation '{operation}' cannot be performed on keyless e
- 'ExecuteUpdate' or 'ExecuteDelete' was called on entity type
- The entity type '{entityType}' was configured to use some st
- The keyless entity type '{entityType}' was configured to use
- The DbFunction '{function}' returns a SqlExpression of type
AI-assisted analysis of dotnet/efcore@3a2006ef56 (2026-08-11).
Data as JSON: /api/errors/915c6c50c7a4ab68.
Report an issue: GitHub.