{"record":{"id":"f0dce07ee2ceab16","repo":"hibernate/hibernate-orm","slug":"association-s-of-entity-s-is-mappedby-a-di","errorCode":null,"errorMessage":"Association '%s' of entity '%s' is 'mappedBy' a different entity and may not explicitly specify the '@JoinColumn'","messagePattern":"Association '(.+?)' of entity '(.+?)' is 'mappedBy' a different entity and may not explicitly specify the '@JoinColumn'","errorType":"exception","errorClass":"AnnotationException","httpStatus":null,"severity":"error","filePath":"hibernate-core/src/main/java/org/hibernate/boot/model/internal/AnnotatedJoinColumn.java","lineNumber":114,"sourceCode":"//\t\tformulaColumn.setContext( buildingContext );\n//\t\tformulaColumn.setPropertyHolder( propertyHolder );\n//\t\tformulaColumn.setPropertyName( getRelativePath( propertyHolder, propertyName ) );\n//\t\tformulaColumn.setJoins( joins );\n\t\tformulaColumn.setParent( parent );\n\t\tformulaColumn.bind();\n\t\treturn formulaColumn;\n\t}\n\n\tstatic AnnotatedJoinColumn buildJoinColumn(\n\t\t\tJoinColumn joinColumn,\n\t\t\tString mappedBy,\n\t\t\tAnnotatedJoinColumns parent,\n\t\t\tPropertyHolder propertyHolder,\n\t\t\tPropertyData inferredData,\n\t\t\tString defaultColumnSuffix) {\n\t\tif ( joinColumn != null ) {\n\t\t\tif ( mappedBy != null ) {\n\t\t\t\tthrow new AnnotationException(\n\t\t\t\t\t\tString.format(\n\t\t\t\t\t\t\t\tLocale.ROOT,\n\t\t\t\t\t\t\t\t\"Association '%s' of entity '%s' is 'mappedBy' a different entity and may not explicitly specify the '@JoinColumn'\",\n\t\t\t\t\t\t\t\tinferredData.getPropertyName(),\n\t\t\t\t\t\t\t\tpropertyHolder.getEntityName() )\n\t\t\t\t);\n\t\t\t}\n\t\t\treturn explicitJoinColumn( joinColumn, parent, inferredData, defaultColumnSuffix );\n\t\t}\n\t\telse {\n\t\t\treturn implicitJoinColumn( parent, inferredData, defaultColumnSuffix );\n\t\t}\n\t}\n\n\tprivate static AnnotatedJoinColumn explicitJoinColumn(\n\t\t\tJoinColumn joinColumn,\n\t\t\tAnnotatedJoinColumns parent,\n\t\t\tPropertyData inferredData,","sourceCodeStart":96,"sourceCodeEnd":132,"githubUrl":"https://github.com/hibernate/hibernate-orm/blob/fad1729dce015f908198d57a8d80274a30f905a5/hibernate-core/src/main/java/org/hibernate/boot/model/internal/AnnotatedJoinColumn.java#L96-L132","documentation":"This association is the INVERSE side of a bidirectional relationship ('mappedBy' points at the owning side), yet it also declares an explicit '@JoinColumn'. In a bidirectional association only the owning side defines the join column; the inverse side mirrors it, so Hibernate forbids the duplicate declaration.","triggerScenarios":"'@OneToMany(mappedBy = \"order\") @JoinColumn(name = \"oid\")' on the collection side while the @ManyToOne side owns the FK; a @ManyToMany(mappedBy=...) with a @JoinTable/@JoinColumn; mappedBy set to a non-null value and joinColumn != null when buildJoinColumn is invoked.","commonSituations":"Adding @JoinColumn to the 'child list' side believing it fixes a FK name (it does not — name it on the @ManyToOne side); converting unidirectional to bidirectional and forgetting to delete the old @JoinColumn; copy-paste between owning and inverse sides.","solutions":["Delete the @JoinColumn from the mappedBy (inverse) side named in the message.","Put the @JoinColumn with the desired FK name on the OWNING side (the @ManyToOne/@OneToOne that does NOT use mappedBy).","Verify the mappedBy string actually names the owning-side property, so the mapping is a valid bidirectional pair."],"exampleFix":"// before\n@Entity\nclass Order {\n    @OneToMany(mappedBy = \"order\")\n    @JoinColumn(name = \"order_id\") // illegal on inverse side\n    List<OrderItem> items;\n}\n\n// after\n@Entity\nclass Order {\n    @OneToMany(mappedBy = \"order\")\n    List<OrderItem> items;\n}\n\n@Entity\nclass OrderItem {\n    @ManyToOne(fetch = FetchType.LAZY)\n    @JoinColumn(name = \"order_id\") // owning side owns the column\n    Order order;\n}","handlingStrategy":"validation","validationCode":"// Guard: inverse (mappedBy) sides must not declare join columns\nfor (Field f : cls.getDeclaredFields()) {\n    OneToMany otm = f.getAnnotation(OneToMany.class);\n    ManyToMany mtm = f.getAnnotation(ManyToMany.class);\n    boolean inverse = (otm != null && !otm.mappedBy().isEmpty())\n                   || (mtm != null && !mtm.mappedBy().isEmpty());\n    if (inverse && (f.isAnnotationPresent(JoinColumn.class) || f.isAnnotationPresent(JoinColumns.class))) {\n        throw new IllegalStateException(cls.getName() + \".\" + f.getName()\n            + \" is mappedBy and must not declare @JoinColumn\");\n    }\n}","typeGuard":null,"tryCatchPattern":"try {\n    factory = cfg.buildSessionFactory();\n} catch (AnnotationException e) {\n    if (e.getMessage().contains(\"may not explicitly specify the '@JoinColumn'\")) {\n        // strip the @JoinColumn from the field named in the message\n        fixInverseSideJoinColumn(e.getMessage());\n    }\n    throw e;\n}","preventionTips":["Rule of thumb: @JoinColumn lives on the @ManyToOne/@OneToOne side; mappedBy side stays annotation-free.","When converting unidirectional to bidirectional, delete the old @JoinColumn in the same commit.","Let a static-analysis or ArchUnit rule flag mappedBy fields carrying @JoinColumn."],"tags":["hibernate","jpa","mappedby","bidirectional","orm-mapping"],"backgroundTag":"mappedby-misuse","analyzedSha":"fad1729dce015f908198d57a8d80274a30f905a5","analyzedAt":"2026-08-22T04:13:57.527Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}