diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/bytecode/duplication/Client.java b/hibernate-core/src/test/java/org/hibernate/orm/test/bytecode/duplication/Client.java
new file mode 100644
index 000000000000..5e32070039a6
--- /dev/null
+++ b/hibernate-core/src/test/java/org/hibernate/orm/test/bytecode/duplication/Client.java
@@ -0,0 +1,26 @@
+/*
+ * SPDX-License-Identifier: Apache-2.0
+ * Copyright Red Hat Inc. and Hibernate Authors
+ */
+package org.hibernate.orm.test.bytecode.duplication;
+
+import jakarta.persistence.EntityManagerFactory;
+import org.hibernate.engine.spi.SessionFactoryImplementor;
+
+/**
+ * To be loaded reflectively...
+ *
+ * @author Steve Ebersole
+ */
+public class Client {
+ public static void execute(EntityManagerFactory emf) {
+ emf.runInTransaction( (entityManager) -> {
+ entityManager.persist( new SimpleEntity( 1, "tester" ) );
+ entityManager.createQuery( "from SimpleEntity" ).getResultList();
+ } );
+ }
+
+ public static void cleanup(EntityManagerFactory emf) {
+ emf.unwrap( SessionFactoryImplementor.class ).getSchemaManager().truncateMappedObjects();
+ }
+}
diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/bytecode/duplication/DuplicateClassTests.java b/hibernate-core/src/test/java/org/hibernate/orm/test/bytecode/duplication/DuplicateClassTests.java
new file mode 100644
index 000000000000..9b84a80e5f47
--- /dev/null
+++ b/hibernate-core/src/test/java/org/hibernate/orm/test/bytecode/duplication/DuplicateClassTests.java
@@ -0,0 +1,110 @@
+/*
+ * SPDX-License-Identifier: Apache-2.0
+ * Copyright Red Hat Inc. and Hibernate Authors
+ */
+package org.hibernate.orm.test.bytecode.duplication;
+
+import jakarta.persistence.EntityManagerFactory;
+import jakarta.persistence.Persistence;
+import org.hibernate.dialect.H2Dialect;
+import org.hibernate.testing.orm.junit.BaseUnitTest;
+import org.hibernate.testing.orm.junit.RequiresDialect;
+import org.jboss.shrinkwrap.api.ArchivePath;
+import org.jboss.shrinkwrap.api.ArchivePaths;
+import org.jboss.shrinkwrap.api.ShrinkWrap;
+import org.jboss.shrinkwrap.api.exporter.ZipExporter;
+import org.jboss.shrinkwrap.api.spec.JavaArchive;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.io.TempDir;
+
+import java.io.File;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLClassLoader;
+
+
+/**
+ * @author Steve Ebersole
+ */
+@BaseUnitTest
+@RequiresDialect( H2Dialect.class )
+public class DuplicateClassTests {
+ private ClassLoader originalTccl;
+
+ @BeforeEach
+ void storeOriginalTccl() {
+ originalTccl = Thread.currentThread().getContextClassLoader();
+ }
+
+ @AfterEach
+ void restoreOriginalTccl() {
+ Thread.currentThread().setContextClassLoader( originalTccl );
+ }
+
+ @Test
+ void testSimple(@TempDir File tempDir)
+ throws MalformedURLException, ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
+ ArchivePath path = ArchivePaths.create( "META-INF/persistence.xml" );
+
+ JavaArchive jar1 = ShrinkWrap.create( JavaArchive.class, "jar1.jar" );
+ jar1.addClasses( SimpleEntity.class );
+ jar1.addAsResource( "units/bytecode/duplication/pu1.xml", path );
+ File jar1File = new File( tempDir, "jar1.jar" );
+ jar1.as( ZipExporter.class ).exportTo( jar1File, true );
+
+ JavaArchive jar2 = ShrinkWrap.create( JavaArchive.class, "jar2.jar" );
+ jar2.addClasses( SimpleEntity.class );
+ jar2.addAsResource( "units/bytecode/duplication/pu2.xml", path );
+ File jar2File = new File( tempDir, "jar2.jar" );
+ jar2.as( ZipExporter.class ).exportTo( jar2File, true );
+
+ URL[] jarUrls = new URL[] {
+ jar1File.toURI().toURL(),
+ jar2File.toURI().toURL()
+ };
+ final URLClassLoader classLoader = new URLClassLoader( jarUrls, getClass().getClassLoader() );
+ Thread.currentThread().setContextClassLoader( classLoader );
+
+ try (EntityManagerFactory emf1 = Persistence.createEntityManagerFactory( "unit-1" )) {
+ executeUseCases( classLoader, emf1 );
+ }
+ try (EntityManagerFactory emf2 = Persistence.createEntityManagerFactory( "unit-2" )) {
+ executeUseCases( classLoader, emf2 );
+ }
+
+ {
+ JavaArchive jar3 = ShrinkWrap.create( JavaArchive.class, "jar3.jar" );
+ jar3.addClasses( SimpleEntity.class );
+ jar3.addAsResource( "units/bytecode/duplication/pu1.xml", path );
+ File jar3File = new File( tempDir, "jar3.jar" );
+ jar3.as( ZipExporter.class ).exportTo( jar3File, true );
+
+ URL[] secondaryUrls = new URL[] { jar3File.toURI().toURL() };
+ final URLClassLoader secondaryClassLoader = new URLClassLoader( secondaryUrls, getClass().getClassLoader() );
+ Thread.currentThread().setContextClassLoader( secondaryClassLoader );
+
+ try (EntityManagerFactory emf3 = Persistence.createEntityManagerFactory( "unit-1" )) {
+ executeUseCases( classLoader, emf3 );
+ }
+ }
+ }
+
+ private void executeUseCases(URLClassLoader classLoader, EntityManagerFactory entityManagerFactory)
+ throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
+ final Class> clientClass = classLoader.loadClass( "org.hibernate.orm.test.bytecode.duplication.Client" );
+ final Method executeMethod = clientClass.getDeclaredMethod( "execute", EntityManagerFactory.class );
+ final Method cleanupMethod = clientClass.getDeclaredMethod( "cleanup", EntityManagerFactory.class );
+
+ try {
+ executeMethod.invoke( null, entityManagerFactory );
+ }
+ finally {
+ cleanupMethod.invoke( null, entityManagerFactory );
+ }
+
+ }
+}
diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/bytecode/duplication/SimpleEntity.java b/hibernate-core/src/test/java/org/hibernate/orm/test/bytecode/duplication/SimpleEntity.java
new file mode 100644
index 000000000000..56cbee32eecb
--- /dev/null
+++ b/hibernate-core/src/test/java/org/hibernate/orm/test/bytecode/duplication/SimpleEntity.java
@@ -0,0 +1,26 @@
+/*
+ * SPDX-License-Identifier: Apache-2.0
+ * Copyright Red Hat Inc. and Hibernate Authors
+ */
+package org.hibernate.orm.test.bytecode.duplication;
+
+import jakarta.persistence.Entity;
+import jakarta.persistence.Id;
+
+/**
+ * @author Steve Ebersole
+ */
+@Entity
+public class SimpleEntity {
+ @Id
+ private Integer id;
+ private String name;
+
+ public SimpleEntity() {
+ }
+
+ public SimpleEntity(Integer id, String name) {
+ this.id = id;
+ this.name = name;
+ }
+}
diff --git a/hibernate-core/src/test/resources/units/bytecode/duplication/pu1.xml b/hibernate-core/src/test/resources/units/bytecode/duplication/pu1.xml
new file mode 100644
index 000000000000..84905641c2d8
--- /dev/null
+++ b/hibernate-core/src/test/resources/units/bytecode/duplication/pu1.xml
@@ -0,0 +1,42 @@
+
+
+
+
+
+ Persistence unit for Hibernate User Guide
+
+
+ org.hibernate.jpa.HibernatePersistenceProvider
+
+ org.hibernate.orm.test.bytecode.duplication.SimpleEntity
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/hibernate-core/src/test/resources/units/bytecode/duplication/pu2.xml b/hibernate-core/src/test/resources/units/bytecode/duplication/pu2.xml
new file mode 100644
index 000000000000..47210f50449e
--- /dev/null
+++ b/hibernate-core/src/test/resources/units/bytecode/duplication/pu2.xml
@@ -0,0 +1,42 @@
+
+
+
+
+
+ Persistence unit for Hibernate User Guide
+
+
+ org.hibernate.jpa.HibernatePersistenceProvider
+
+ org.hibernate.orm.test.bytecode.duplication.SimpleEntity
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+