{"record":{"id":"b9f36265e8d4ba2e","repo":"dotnet/efcore","slug":"entity-type-entitytype-is-an-optional-dependen","errorCode":null,"errorMessage":"Entity type '{entityType}' is an optional dependent using table sharing and containing other dependents without any required non shared property to identify whether the entity exists. If all nullable properties contain a 'null' value in database then an object instance won't be created in the query causing nested dependent's values to be lost. Add a required property to create instances with 'null' values for other properties or mark the incoming navigation as required to always create an instance.","messagePattern":"Entity type '(.+?)' is an optional dependent using table sharing and containing other dependents without any required non shared property to identify whether the entity exists\\. If all nullable properties contain a 'null' value in database then an object instance won't be created in the query causing nested dependent's values to be lost\\. Add a required property to create instances with 'null' values for other properties or mark the incoming navigation as required to always create an instance\\.","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/EFCore.Relational/Infrastructure/RelationalModelValidator.cs","lineNumber":1102,"sourceCode":"                    continue;\n                }\n\n                var columnName = property.GetColumnName(tableIdentifier);\n                if (columnName != null)\n                {\n                    if (!principalColumns.Contains(columnName))\n                    {\n                        requiredNonSharedColumnFound = true;\n                        break;\n                    }\n                }\n            }\n\n            if (!requiredNonSharedColumnFound)\n            {\n                if (entityType.GetReferencingForeignKeys().Select(e => e.DeclaringEntityType).Any(t => mappedTypes.Contains(t)))\n                {\n                    throw new InvalidOperationException(\n                        RelationalStrings.OptionalDependentWithDependentWithoutIdentifyingProperty(entityType.DisplayName()));\n                }\n\n                logger.OptionalDependentWithoutIdentifyingPropertyWarning(entityType);\n            }\n        }\n\n        (List<IEntityType> EntityTypes, bool Optional) GetPrincipalEntityTypes(IEntityType entityType)\n        {\n            if (!principalEntityTypesMap.TryGetValue(entityType, out var tuple))\n            {\n                var list = new List<IEntityType>();\n                var optional = false;\n                foreach (var foreignKey in entityType.FindForeignKeys(entityType.FindPrimaryKey()!.Properties))\n                {\n                    var principalEntityType = foreignKey.PrincipalEntityType;\n                    if (foreignKey.PrincipalEntityType.IsAssignableFrom(foreignKey.DeclaringEntityType)\n                        || !mappedTypes.Contains(principalEntityType))","sourceCodeStart":1084,"sourceCodeEnd":1120,"githubUrl":"https://github.com/dotnet/efcore/blob/3a2006ef569de08368d59db5e1468aa8f407e4f8/src/EFCore.Relational/Infrastructure/RelationalModelValidator.cs#L1084-L1120","documentation":"Thrown by ValidateOptionalDependents when an optional dependent (owned type, nullable navigation) is shared-table-mapped with the principal AND itself has referencing foreign keys whose declaring entity types are also in mappedTypes — i.e. nested owned dependents — yet the optional dependent has no required non-shared identifying column. Without such a column, EF cannot distinguish a null instance from an all-null instance, and would silently lose nested dependents during query, so the validator throws rather than corrupt data.","triggerScenarios":"An owned entity type configured with .OwnsOne(...) where the navigation is optional (nullable), sharing the principal's table, and that owned type itself has .OwnsOne(...) children mapped to the same table, but every column on the optional dependent is nullable (so all-null is a valid row). The validator's requiredNonSharedColumnFound flag stays false AND GetReferencingForeignKeys().Any(... mappedTypes.Contains) is true -> throw.","commonSituations":"Optional owned address with optional owned contact-info nested in it, all columns nullable; refactoring an entity to owned without marking a sentinel required column; TPH with optional complex types.","solutions":["Add at least one required (non-nullable, non-shared) property to the optional dependent so EF can detect its existence: builder.OwnsOne(e => e.Address, a => { a.Property(x => x.Street).IsRequired(); }).","Mark the navigation to the dependent as required: builder.OwnsOne(e => e.Address, a => a.Navigation(e => e.Address).IsRequired()) — but then it is no longer optional.","Restructure so the nested dependents live on a separate table or are not mapped to the same shared table."],"exampleFix":"// before\nbuilder.OwnsOne(e => e.Address, a =>\n{\n    a.ToTable(\"Customers\");\n    a.Property(x => x.Street);  // nullable\n    a.OwnsOne(x => x.Geo, g => g.Property(p => p.Lat)); // nested dependent\n});\n\n// after\nbuilder.OwnsOne(e => e.Address, a =>\n{\n    a.ToTable(\"Customers\");\n    a.Property(x => x.Street).IsRequired(); // sentinel for existence\n    a.OwnsOne(x => x.Geo, g => g.Property(p => p.Lat));\n});","handlingStrategy":"validation","validationCode":"// Walk owned types and warn on optional dependents with nested dependents but no sentinel.\nforeach (var et in model.GetEntityTypes())\n{\n    var owns = et.GetReferencingForeignKeys()\n        .Where(fk => fk.IsOwnership && fk.DeclaringEntityType.IsMappedToTable());\n    foreach (var fk in owns)\n    {\n        var owned = fk.DeclaringEntityType;\n        bool navigationOptional = fk.Properties.Any(p => p.IsNullable);\n        bool hasNestedDependent = owned.GetReferencingForeignKeys()\n            .Any(f => f.IsOwnership);\n        bool hasRequiredNonShared = owned.GetProperties()\n            .Any(p => !p.IsNullable && !p.IsShadowProperty());\n        if (navigationOptional && hasNestedDependent && !hasRequiredNonShared)\n            Console.WriteLine($\"{owned.Name} is an optional dependent with nested dependents and no sentinel property.\");\n    }\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Add an IsRequired() property on any optional owned type that itself owns other types.","Prefer marking the navigation as required when the dependent must always exist.","Avoid nesting optional owned types without an identifying non-nullable column."],"tags":["ef-core","owned-types","table-sharing","model-validation","optional-dependent"],"backgroundTag":null,"analyzedSha":"3a2006ef569de08368d59db5e1468aa8f407e4f8","analyzedAt":"2026-08-11T23:42:04.146Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}