dotnet/efcore · error · InvalidOperationException
ExecuteDeleteOnNonEntityType
ExecuteDeleteOnNonEntityType
Error message
The operation 'ExecuteDelete' requires an entity type which corresponds to the database table to be modified. The current operation is being applied on a non-entity projection. Remove any projection to non-entity types.
What it means
Thrown by TranslateExecuteDelete when, after pruning includes, the query shaper does not project an IEntityType - e.g. it projects an anonymous type, a DTO, or a scalar. ExecuteDelete must target a real entity mapped to a table; it cannot operate on an arbitrary projection.
Source
Thrown at src/EFCore.Relational/Query/RelationalQueryableMethodTranslatingExpressionVisitor.ExecuteDelete.cs:17
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using Microsoft.EntityFrameworkCore.Query.SqlExpressions;
namespace Microsoft.EntityFrameworkCore.Query;
public partial class RelationalQueryableMethodTranslatingExpressionVisitor
{
/// <inheritdoc />
protected override DeleteExpression TranslateExecuteDelete(ShapedQueryExpression source)
{
source = source.UpdateShaperExpression(new IncludePruner().Visit(source.ShaperExpression));
if (source.ShaperExpression is not StructuralTypeShaperExpression { StructuralType: IEntityType entityType } shaper)
{
throw new InvalidOperationException(RelationalStrings.ExecuteDeleteOnNonEntityType);
}
if (entityType.IsMappedToJson())
{
throw new InvalidOperationException(
RelationalStrings.ExecuteOperationOnOwnedJsonIsNotSupported("ExecuteDelete", entityType.DisplayName()));
}
switch (entityType.GetMappingStrategy())
{
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():View on GitHub (pinned to dbf9771522)
Solutions
- Remove the Select/anonymous projection so the query returns the entity type directly: db.Blogs.ExecuteDeleteAsync().
- If you projected for filtering, move the filter into Where and drop the Select: db.Blogs.Where(b => ids.Contains(b.Id)).ExecuteDeleteAsync().
- Ensure the query root is the entity DbSet rather than a computed projection.
- If you must delete based on a DTO, resolve the entity keys and delete via the entity DbSet.
Example fix
// before
await db.Blogs.Select(b => new Dto { Id = b.Id }).ExecuteDeleteAsync();
// after
await db.Blogs.ExecuteDeleteAsync();
// or with a filter instead of a projection
await db.Blogs.Where(b => b.Rating < 3).ExecuteDeleteAsync(); Defensive patterns
Strategy: validation
Validate before calling
// Ensure no projection (Select/anonymous) sits between the DbSet and ExecuteDelete var query = db.Blogs.Where(b => b.Rating < 3); // entity-typed, not projected await query.ExecuteDeleteAsync();
Try / catch
try { await query.ExecuteDeleteAsync(); }
catch (InvalidOperationException ex) when (ex.Message.Contains("non-entity projection"))
{
// re-issue against the entity DbSet with just a predicate
await db.Blogs.Where(predicate).ExecuteDeleteAsync();
} Prevention
- Never put Select between a DbSet and ExecuteDelete/ExecuteUpdate.
- Move filtering logic into Where, not Select.
- Ensure the query root is the entity DbSet.
- Write integration tests covering each bulk delete path.
When it happens
Trigger: Calling ExecuteDelete on a query that projects to a non-entity shape: db.Blogs.Select(b => new { b.Id }).ExecuteDeleteAsync(), or db.Blogs.Select(b => b.Name).ExecuteDeleteAsync(), or projecting a complex type / owned type directly.
Common situations: Composing Select/anonymous-type projections before ExecuteDelete; reusing a query builder that returns DTOs; misunderstanding that ExecuteDelete needs the entity shape, not a derived projection.
Related errors
- ExecuteOperationOnOwnedJsonIsNotSupported
- ExecuteOperationOnTPT
- ExecuteOperationOnTPC
- ExecuteUpdateDeleteOnEntityNotMappedToTable
- ExecuteOperationOnEntitySplitting
AI-assisted analysis of dotnet/efcore@dbf9771522 (2026-08-06).
Data as JSON: /api/errors/def0241f8d0daa93.
Report an issue: GitHub.