{"record":{"id":"3495b0ed40208fac","repo":"dotnet/efcore","slug":"the-json-property-name-should-only-be-configured-o","errorCode":null,"errorMessage":"The JSON property name should only be configured on nested owned navigations.","messagePattern":"The JSON property name should only be configured on nested owned navigations\\.","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/EFCore.Relational/Extensions/RelationalOwnedNavigationBuilderExtensions.cs","lineNumber":132,"sourceCode":"        return builder;\n    }\n\n    /// <summary>\n    ///     Configures the navigation of an entity mapped to a JSON column, mapping the navigation to a specific JSON property,\n    ///     rather than using the navigation name.\n    /// </summary>\n    /// <param name=\"navigationBuilder\">The builder for the navigation being configured.</param>\n    /// <param name=\"name\">JSON property name to be used.</param>\n    /// <returns>The same builder instance so that multiple calls can be chained.</returns>\n    public static OwnedNavigationBuilder HasJsonPropertyName(\n        this OwnedNavigationBuilder navigationBuilder,\n        string? name)\n    {\n        Check.NullButNotEmpty(name);\n\n        if (!navigationBuilder.Metadata.PrincipalEntityType.IsOwned())\n        {\n            throw new InvalidOperationException(\n                RelationalStrings.JsonPropertyNameShouldBeConfiguredOnNestedNavigation);\n        }\n\n        navigationBuilder.Metadata.DeclaringEntityType.SetJsonPropertyName(name);\n\n        return navigationBuilder;\n    }\n\n    /// <summary>\n    ///     Configures the navigation of an entity mapped to a JSON column, mapping the navigation to a specific JSON property,\n    ///     rather than using the navigation name.\n    /// </summary>\n    /// <param name=\"navigationBuilder\">The builder for the navigation being configured.</param>\n    /// <param name=\"name\">JSON property name to be used.</param>\n    /// <returns>The same builder instance so that multiple calls can be chained.</returns>\n    public static OwnedNavigationBuilder<TSource, TTarget> HasJsonPropertyName<TSource, TTarget>(\n        this OwnedNavigationBuilder<TSource, TTarget> navigationBuilder,\n        string? name)","sourceCodeStart":114,"sourceCodeEnd":150,"githubUrl":"https://github.com/dotnet/efcore/blob/dbf9771522148d61a2467854921bd5dc6f6e6916/src/EFCore.Relational/Extensions/RelationalOwnedNavigationBuilderExtensions.cs#L114-L150","documentation":"OwnedNavigationBuilder.HasJsonPropertyName() may only be called on a NESTED owned navigation — one whose principal entity type is itself owned (RelationalOwnedNavigationBuilderExtensions.cs:132, RelationalStrings.JsonPropertyNameShouldBeConfiguredOnNestedNavigation). On the outermost owned navigation the principal is the owning (non-owned) entity, so configuring a JSON property name there is meaningless; the JSON column name is configured via ToJson instead.","triggerScenarios":"Calling builder.HasJsonPropertyName(...) on the OwnedNavigationBuilder returned directly by EntityTypeBuilder.OwnsOne/OwnsMany (the top-level ownership), where PrincipalEntityType is the owner and not owned.","commonSituations":"Applying a generic JSON-property-naming convention by iterating all owned navigations without skipping the outermost; migrating from a per-navigation column name to JSON mapping and calling HasJsonPropertyName at the wrong level.","solutions":["Call HasJsonPropertyName only one level deep — on an OwnedNavigationBuilder obtained from a nested OwnsOne/OwnsMany inside another owned type.","To name the JSON column itself, use builder.ToJson(\"columnName\") on the outermost owned navigation.","Guard generic loops: if (!ownedNav.Metadata.PrincipalEntityType.IsOwned()) use ToJson; else use HasJsonPropertyName."],"exampleFix":"// before\nmodelBuilder.Entity<Customer>().OwnsOne(c => c.Address, a =>\n{\n    a.HasJsonPropertyName(\"addr\");   // throws: Address's principal (Customer) is not owned\n});\n\n// after\nmodelBuilder.Entity<Customer>().OwnsOne(c => c.Address, a =>\n{\n    a.ToJson(\"Address\");            // name the JSON column at the top level\n    a.OwnsOne(x => x.Geo, g => g.HasJsonPropertyName(\"geo\")); // nested: ok\n});","handlingStrategy":"validation","validationCode":"// Only call HasJsonPropertyName on nested owned navigations.\nAction<OwnedNavigationBuilder<Customer, Address>> configure = a =>\n{\n    a.ToJson(\"Address\"); // top level: name the JSON column\n    if (a.Metadata.PrincipalEntityType.IsOwned())\n    {\n        a.HasJsonPropertyName(\"...\"); // would only be valid if nested\n    }\n};","typeGuard":"static bool IsNestedOwned(OwnedNavigationBuilder b) => b.Metadata.PrincipalEntityType.IsOwned();","tryCatchPattern":null,"preventionTips":["Use ToJson on the outermost owned navigation to name the JSON column.","Guard generic JSON-property-naming loops with PrincipalEntityType.IsOwned().","Reserve HasJsonPropertyName for nested owned navigations only."],"tags":["json-mapping","owned-types","model-building","navigation"],"analyzedSha":"dbf9771522148d61a2467854921bd5dc6f6e6916","analyzedAt":"2026-08-06T20:46:03.226Z","schemaVersion":2},"datasetVersion":"2026-08-07T03:17:09.362Z"}