{"record":{"id":"371459f107f5d181","repo":"dotnet/efcore","slug":"the-property-entitytype-property-is-mapped-t-371459","errorCode":null,"errorMessage":"The property '{entityType}.{property}' is mapped to a parameter of the stored procedure '{sproc}', but only concurrency token and key properties are supported for Delete stored procedures.","messagePattern":"The property '(.+?)\\.(.+?)' is mapped to a parameter of the stored procedure '(.+?)', but only concurrency token and key properties are supported for Delete stored procedures\\.","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/EFCore.Relational/Infrastructure/RelationalModelValidator.cs","lineNumber":818,"sourceCode":"                                && p.ForOriginalValue != parameter.ForOriginalValue\n                                && p.Direction != ParameterDirection.Input))\n                        {\n                            throw new InvalidOperationException(\n                                RelationalStrings.StoredProcedureOutputParameterConflict(\n                                    entityType.DisplayName(), parameter.PropertyName, storeObjectIdentifier.DisplayName()));\n                        }\n\n                        throw new InvalidOperationException(\n                            RelationalStrings.StoredProcedureOutputParameterNotGenerated(\n                                entityType.DisplayName(), parameter.PropertyName, storeObjectIdentifier.DisplayName()));\n                    }\n\n                    break;\n                case StoreObjectType.DeleteStoredProcedure:\n                    if (!property!.IsPrimaryKey()\n                        && !property.IsConcurrencyToken)\n                    {\n                        throw new InvalidOperationException(\n                            RelationalStrings.StoredProcedureDeleteNonKeyProperty(\n                                entityType.DisplayName(), parameter.PropertyName, storeObjectIdentifier.DisplayName()));\n                    }\n\n                    break;\n                default:\n                    Check.DebugFail(\"Unexpected stored procedure type: \" + storeObjectIdentifier.StoreObjectType);\n                    break;\n            }\n        }\n\n        foreach (var resultColumn in sproc.ResultColumns)\n        {\n            if (resultColumn.PropertyName == null)\n            {\n                continue;\n            }\n","sourceCodeStart":800,"sourceCodeEnd":836,"githubUrl":"https://github.com/dotnet/efcore/blob/3a2006ef569de08368d59db5e1468aa8f407e4f8/src/EFCore.Relational/Infrastructure/RelationalModelValidator.cs#L800-L836","documentation":"Thrown when a DELETE stored procedure mapping has a parameter bound to a property that is neither a primary key part nor a concurrency token. Delete sprocs only identify the row(s) to remove, so EF restricts delete parameters to PK and row-version columns. Any other property mapped as a delete parameter is rejected.","triggerScenarios":"entityType.DeleteUsingStoredProcedure(...).HasParameter(p => p.SomeNonKeyColumn) where SomeNonKeyColumn is not part of the PK and not marked IsConcurrencyToken. Also surfaces when a current-value parameter (rather than original-value) is used on delete, or when a base-type property leaks into a derived delete sproc.","commonSituations":"Reusing a generic sproc configuration builder across insert/update/delete and forgetting to drop non-key parameters for delete; trying to pass an audit column to the delete sproc; mapping an FK column on delete.","solutions":["Remove .HasParameter(p => p.NonKeyColumn) from the DeleteUsingStoredProcedure configuration.","If the value is a row-version, mark the property as a concurrency token: builder.Property(p => p.RowVersion).IsRowVersion() / IsConcurrencyToken(), and use HasOriginalValueParameter.","If you need additional filtering on delete, expose it as a non-property parameter (a literal/value parameter) rather than a property-bound one, or handle it inside the sproc body."],"exampleFix":"// before\nentityType.DeleteUsingStoredProcedure(\"DeleteOrder\",\n    sp =>\n    {\n        sp.HasParameter(o => o.OrderId);\n        sp.HasParameter(o => o.Status); // Status is not key/concurrency token -> error\n    });\n\n// after\nentityType.DeleteUsingStoredProcedure(\"DeleteOrder\",\n    sp => sp.HasParameter(o => o.OrderId));","handlingStrategy":"validation","validationCode":"foreach (var et in model.GetEntityTypes())\n{\n    var deleteSproc = et.GetDeleteStoredProcedure();\n    if (deleteSproc == null) continue;\n    foreach (var p in deleteSproc.Parameters)\n    {\n        if (p.PropertyName is string name)\n        {\n            var prop = et.FindProperty(name);\n            if (prop is { IsPrimaryKey: false } && prop?.IsConcurrencyToken == false)\n                Console.WriteLine($\"{et.Name}.{name} cannot be a delete parameter (not key/concurrency).\");\n        }\n    }\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Build delete sproc configs to accept only PK and row-version parameters.","Use HasOriginalValueParameter for concurrency tokens on delete.","Keep separate fluent blocks per sproc kind; never share one across insert/update/delete."],"tags":["ef-core","stored-procedures","model-validation","delete"],"backgroundTag":null,"analyzedSha":"3a2006ef569de08368d59db5e1468aa8f407e4f8","analyzedAt":"2026-08-11T23:42:04.146Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}