{"record":{"id":"64225a2768ecaea5","repo":"hibernate/hibernate-orm","slug":"collection-is-annotated-both-mapkey-and","errorCode":null,"errorMessage":"Collection '{}' is annotated both '@MapKey' and '@MapKeyColumn'","messagePattern":"Collection '(.+?)' is annotated both '@MapKey' and '@MapKeyColumn'","errorType":"exception","errorClass":"AnnotationException","httpStatus":null,"severity":"error","filePath":"hibernate-core/src/main/java/org/hibernate/boot/model/internal/CollectionBinder.java","lineNumber":1144,"sourceCode":"\t\tcollection.setInverse( isUnowned );\n\n\t\t//TODO reduce tableBinder != null and oneToMany\n\t\tscheduleSecondPass( isUnowned );\n\t\tgetMetadataCollector().addCollectionBinding( collection );\n\t\tbindProperty();\n\t}\n\n\tprivate boolean isUnownedCollection() {\n\t\treturn mappedBy != null;\n\t}\n\n\tprivate boolean isMutable() {\n\t\treturn !property.hasDirectAnnotationUsage( Immutable.class );\n\t}\n\n\tprivate void checkMapKeyColumn() {\n\t\tif ( property.hasDirectAnnotationUsage( MapKeyColumn.class ) && hasMapKeyProperty ) {\n\t\t\tthrow new AnnotationException( \"Collection '\" + qualify( propertyHolder.getPath(), propertyName )\n\t\t\t\t\t+ \"' is annotated both '@MapKey' and '@MapKeyColumn'\" );\n\t\t}\n\t}\n\n\tprivate void scheduleSecondPass(boolean isMappedBy) {\n\t\tfinal var metadataCollector = getMetadataCollector();\n\t\t//many to many may need some second pass information\n\t\tif ( !oneToMany && isMappedBy ) {\n\t\t\tmetadataCollector.addMappedBy( getElementType().getName(), mappedBy, propertyName );\n\t\t}\n\n\t\tif ( inheritanceStatePerClass == null) {\n\t\t\tthrow new AssertionFailure( \"inheritanceStatePerClass not set\" );\n\t\t}\n\t\tmetadataCollector.addSecondPass( getSecondPass(), !isMappedBy );\n\t}\n\n\tprivate void bindOptimisticLock(boolean isMappedBy) {","sourceCodeStart":1126,"sourceCodeEnd":1162,"githubUrl":"https://github.com/hibernate/hibernate-orm/blob/fad1729dce015f908198d57a8d80274a30f905a5/hibernate-core/src/main/java/org/hibernate/boot/model/internal/CollectionBinder.java#L1126-L1162","documentation":"A Map-valued collection must define exactly one key-mapping strategy: @MapKey (key is a property of the target entity or the target's primary key) or @MapKeyColumn (key is an explicit column of the collection table). When hasMapKeyProperty is already true and @MapKeyColumn is also present, checkMapKeyColumn throws this AnnotationException.","triggerScenarios":"A map collection property carries both @MapKey (or otherwise gets a map-key property bound) and @MapKeyColumn directly on the property; the check runs during bind() via checkMapKeyColumn().","commonSituations":"Copy-paste while switching key strategies from property-based to column-based; adding @MapKeyColumn to fix a key-column name without removing an older @MapKey; IDE suggesting both annotations for map mappings.","solutions":["If the key is a column in the collection table, keep only @MapKeyColumn","If the key is a target-entity property, keep only @MapKey(name = \"...\")","For element-collection maps, also consider @MapKeyJoinColumn for entity-typed keys instead of stacking annotations"],"exampleFix":"// before\n@ManyToMany\n@MapKey(name = \"isbn\")          // key = property of target\n@MapKeyColumn(name = \"key_col\") // error: conflicts with @MapKey\nMap<String, Book> books;\n\n// after\n@ManyToMany\n@MapKeyColumn(name = \"key_col\") // choose ONE key mapping strategy\nMap<String, Book> books;","handlingStrategy":"validation","validationCode":"// Reject @MapKey together with @MapKeyColumn\nstatic void checkMapKeyConflicts(Class<?>... entities) {\n    for ( Class<?> c : entities ) {\n        for ( Field f : c.getDeclaredFields() ) {\n            if ( f.isAnnotationPresent( MapKey.class )\n                    && f.isAnnotationPresent( MapKeyColumn.class ) ) {\n                throw new IllegalStateException( \"Both @MapKey and @MapKeyColumn on \"\n                    + c.getName() + \".\" + f.getName() );\n            }\n        }\n    }\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Pick one map-key strategy per map: @MapKey (property/PK), @MapKeyColumn (column), or @MapKeyJoinColumn (entity key)","When changing key strategy, delete the old key annotation in the same edit","Cover every map-valued collection in the bootstrap smoke test"],"tags":["hibernate","jpa","map-key","map-key-column","collection-mapping","annotation-binding"],"backgroundTag":"mapkey-annotation-conflict","analyzedSha":"fad1729dce015f908198d57a8d80274a30f905a5","analyzedAt":"2026-08-22T04:13:57.527Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}