{"record":{"id":"fd610111c4a37229","repo":"hibernate/hibernate-orm","slug":"duplicate-table-mapping","errorCode":null,"errorMessage":"Duplicate table mapping '{}'","messagePattern":"Duplicate table mapping '(.+?)'","errorType":"exception","errorClass":"DuplicateMappingException","httpStatus":null,"severity":"error","filePath":"hibernate-core/src/main/java/org/hibernate/boot/internal/InFlightMetadataCollectorImpl.java","lineNumber":962,"sourceCode":"\t\t// being set into the generated table (mainly to avoid later NPE), but for now we need to keep that :(\n\t\tfinal Identifier logicalName = name != null ? database.toIdentifier( name ) : null;\n\t\tif ( subselectFragment != null ) {\n\t\t\treturn namespace.createDenormalizedTable(\n\t\t\t\t\tlogicalName,\n\t\t\t\t\tphysicalName -> new DenormalizedTable(\n\t\t\t\t\t\t\tbuildingContext.getCurrentContributorName(),\n\t\t\t\t\t\t\tnamespace,\n\t\t\t\t\t\t\tlogicalName,\n\t\t\t\t\t\t\tsubselectFragment,\n\t\t\t\t\t\t\tisAbstract,\n\t\t\t\t\t\t\tincludedTable\n\t\t\t\t\t)\n\t\t\t);\n\t\t}\n\t\telse {\n\t\t\tif ( namespace.locateTable( logicalName ) != null ) {\n\t\t\t\tassert logicalName != null;\n\t\t\t\tthrow new DuplicateMappingException( DuplicateMappingException.Type.TABLE, logicalName.toString() );\n\t\t\t}\n\t\t\telse {\n\t\t\t\treturn namespace.createDenormalizedTable(\n\t\t\t\t\t\tlogicalName,\n\t\t\t\t\t\tphysicalTableName -> new DenormalizedTable(\n\t\t\t\t\t\t\t\tbuildingContext.getCurrentContributorName(),\n\t\t\t\t\t\t\t\tnamespace,\n\t\t\t\t\t\t\t\tphysicalTableName,\n\t\t\t\t\t\t\t\tisAbstract,\n\t\t\t\t\t\t\t\tincludedTable\n\t\t\t\t\t\t)\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n\n\n\t// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~","sourceCodeStart":944,"sourceCodeEnd":980,"githubUrl":"https://github.com/hibernate/hibernate-orm/blob/fad1729dce015f908198d57a8d80274a30f905a5/hibernate-core/src/main/java/org/hibernate/boot/internal/InFlightMetadataCollectorImpl.java#L944-L980","documentation":"DuplicateMappingException(Type.TABLE): the table-registration path (the snippet is the denormalized-table branch used by secondary tables and joined inheritance) found that a table with the same logical name already exists in the same catalog/schema namespace. Tables are keyed by (catalog, schema, name), so a collision means two mappings claim one table slot and bootstrap aborts.","triggerScenarios":"A @SecondaryTable whose name equals the entity's primary @Table or another secondary table; joined-subclass hierarchies with explicitly colliding table names; naming-strategy normalization making two distinct declarations converge to one name.","commonSituations":"Copy-pasted entities, refactors that renamed a primary table onto an existing secondary/join table name, and PhysicalNamingStrategies that add/strip prefixes so different declarations collapse to the same physical name.","solutions":["Rename one of the colliding tables: compare the name in the message against every @Table, @SecondaryTable and @JoinTable declaration","Verify a PhysicalNamingStrategy is not making two different logical names equal after normalization","Ensure joined subclasses do not restate the parent table's name","Re-run bootstrap after the rename; table duplicates always fail the build"],"exampleFix":"// before — secondary table collides with the primary table\n@Entity\n@Table(name = \"orders\")\n@SecondaryTable(name = \"orders\", pkJoinColumns = @PrimaryKeyJoinColumn(name = \"id\"))\n\n// after\n@Entity\n@Table(name = \"orders\")\n@SecondaryTable(name = \"order_details\", pkJoinColumns = @PrimaryKeyJoinColumn(name = \"order_id\"))","handlingStrategy":"try-catch","validationCode":"static void assertNoDuplicateTableNames( Class<?>... entityClasses ) {\n    final Set<String> seen = new HashSet<>();\n    for ( final Class<?> c : entityClasses ) {\n        final Table t = c.getAnnotation( Table.class );\n        if ( t != null && !seen.add( t.catalog() + '.' + t.schema() + '.' + t.name() ) ) {\n            throw new IllegalStateException( \"Duplicate table name: \" + t.name() + \" on \" + c );\n        }\n        for ( final SecondaryTable st : c.getAnnotationsByType( SecondaryTable.class ) ) {\n            if ( !seen.add( st.catalog() + '.' + st.schema() + '.' + st.name() ) ) {\n                throw new IllegalStateException( \"Duplicate table name: \" + st.name() + \" on \" + c );\n            }\n        }\n    }\n}","typeGuard":null,"tryCatchPattern":"try {\n    sessionFactory = metadata.buildSessionFactory();\n} catch ( DuplicateMappingException e ) {\n    if ( e.getType() == DuplicateMappingException.Type.TABLE ) {\n        throw new IllegalStateException( \"Duplicate table mapping '\" + e.getName() + \"' — check @Table/@SecondaryTable/@JoinTable names and the naming strategy\", e );\n    }\n    throw e;\n}","preventionTips":["Keep table names unique across the whole persistence unit, not just per entity","Review PhysicalNamingStrategy changes that add or strip prefixes","Do not restate the parent table name on joined subclasses","Include the complete entity set in the CI bootstrap test"],"tags":["hibernate","orm","jpa","java","bootstrap","table-mapping","duplicate-mapping"],"backgroundTag":"duplicate-table-mapping","analyzedSha":"fad1729dce015f908198d57a8d80274a30f905a5","analyzedAt":"2026-08-22T04:13:57.527Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}