{"record":{"id":"47cf4a945dd3342c","repo":"dotnet/efcore","slug":"the-operation-operation-is-being-applied-on-en","errorCode":null,"errorMessage":"The operation '{operation}' is being applied on entity type '{entityType}', which is using the TPT mapping strategy. 'ExecuteDelete'/'ExecuteUpdate' operations on hierarchies mapped as TPT are not supported.","messagePattern":"The operation '(.+?)' is being applied on entity type '(.+?)', which is using the TPT mapping strategy\\. 'ExecuteDelete'/'ExecuteUpdate' operations on hierarchies mapped as TPT are not supported\\.","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/EFCore.Relational/Query/RelationalQueryableMethodTranslatingExpressionVisitor.ExecuteDelete.cs","lineNumber":29,"sourceCode":"    protected override DeleteExpression TranslateExecuteDelete(ShapedQueryExpression source)\n    {\n        source = source.UpdateShaperExpression(new IncludePruner().Visit(source.ShaperExpression));\n\n        if (source.ShaperExpression is not StructuralTypeShaperExpression { StructuralType: IEntityType entityType } shaper)\n        {\n            throw new InvalidOperationException(RelationalStrings.ExecuteDeleteOnNonEntityType);\n        }\n\n        if (entityType.IsMappedToJson())\n        {\n            throw new InvalidOperationException(\n                RelationalStrings.ExecuteOperationOnOwnedJsonIsNotSupported(\"ExecuteDelete\", entityType.DisplayName()));\n        }\n\n        switch (entityType.GetMappingStrategy())\n        {\n            case RelationalAnnotationNames.TptMappingStrategy:\n                throw new InvalidOperationException(\n                    RelationalStrings.ExecuteOperationOnTPT(\n                        nameof(EntityFrameworkQueryableExtensions.ExecuteDelete),\n                        entityType.DisplayName()));\n\n            // Note that we do allow TPC if the target is a leaf type\n            case RelationalAnnotationNames.TpcMappingStrategy when entityType.GetDirectlyDerivedTypes().Any():\n                throw new InvalidOperationException(\n                    RelationalStrings.ExecuteOperationOnTPC(\n                        nameof(EntityFrameworkQueryableExtensions.ExecuteDelete),\n                        entityType.DisplayName()));\n        }\n\n        // Find the table model that maps to the entity type; there must be exactly one (e.g. no entity splitting).\n        var targetTable = entityType.GetTableMappings().ToList() switch\n        {\n            [] => throw new InvalidOperationException(\n                RelationalStrings.ExecuteUpdateDeleteOnEntityNotMappedToTable(entityType.DisplayName())),\n            [var singleTableMapping] => singleTableMapping.Table,","sourceCodeStart":11,"sourceCodeEnd":47,"githubUrl":"https://github.com/dotnet/efcore/blob/3a2006ef569de08368d59db5e1468aa8f407e4f8/src/EFCore.Relational/Query/RelationalQueryableMethodTranslatingExpressionVisitor.ExecuteDelete.cs#L11-L47","documentation":"TranslateExecuteDelete switches on GetMappingStrategy() and throws for TPT (table-per-type). In TPT each type has its own table, so a single parametrized DELETE statement cannot correctly remove a hierarchy's rows across multiple tables; EF therefore refuses ExecuteDelete/ExecuteUpdate on TPT hierarchies.","triggerScenarios":"context.Set<TptBase>().ExecuteDelete() (or on a derived type) where the hierarchy is mapped with .UseTptMappingStrategy(); similarly ExecuteUpdate on the same. Triggered as soon as the target entity type's mapping strategy resolves to TPT.","commonSituations":"Existing TPT hierarchies where a developer expects bulk delete to work; switching a hierarchy from TPH to TPT and re-running a previously-working ExecuteDelete.","solutions":["Switch the hierarchy to TPH (single table) or TPC if bulk delete/update is required.","Issue per-table raw SQL deletes (base + each subtype) in the correct order via Database.ExecuteSqlRaw.","Load entities and use RemoveRange + SaveChanges, which correctly deletes across TPT tables.","Target a specific concrete leaf type with its own mapping that is not TPT."],"exampleFix":"// before (TPT hierarchy)\nawait db.Set<TptBase>().Where(b => b.Stale).ExecuteDeleteAsync();\n// after (per-table raw SQL or SaveChanges)\nforeach (var id in ids) { var e = await db.Set<TptBase>().FindAsync(id); if (e != null) db.Remove(e); }\nawait db.SaveChangesAsync();","handlingStrategy":"validation","validationCode":"// Reject ExecuteDelete/ExecuteUpdate on TPT hierarchies before calling.\nvar et = db.Model.FindEntityType(typeof(TEntity))!;\nvar strategy = et.GetMappingStrategy();\nif (strategy == RelationalAnnotationNames.TptMappingStrategy)\n    throw new InvalidOperationException(\n        \"ExecuteDelete/ExecuteUpdate is not supported on TPT hierarchies; use TPH/TPC or SaveChanges/raw SQL.\");","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Pick TPH or TPC if bulk delete/update is a common operation in the hierarchy.","Use SaveChanges or raw per-table SQL when TPT is mandatory.","Document mapping-strategy constraints for bulk operations in the team's data-access guidelines."],"tags":["efcore","executedelete","tpt","inheritance","mapping"],"backgroundTag":null,"analyzedSha":"3a2006ef569de08368d59db5e1468aa8f407e4f8","analyzedAt":"2026-08-11T23:42:04.146Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}