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

  1. Remove the Select/anonymous projection so the query returns the entity type directly: db.Blogs.ExecuteDeleteAsync().
  2. If you projected for filtering, move the filter into Where and drop the Select: db.Blogs.Where(b => ids.Contains(b.Id)).ExecuteDeleteAsync().
  3. Ensure the query root is the entity DbSet rather than a computed projection.
  4. 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

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


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