starting to make openjpa-knight
diff --git a/arthur-impl/src/main/java/org/apache/geronimo/arthur/impl/nativeimage/generator/ConfigurationGenerator.java b/arthur-impl/src/main/java/org/apache/geronimo/arthur/impl/nativeimage/generator/ConfigurationGenerator.java
index 84796bc..b092e1d 100644
--- a/arthur-impl/src/main/java/org/apache/geronimo/arthur/impl/nativeimage/generator/ConfigurationGenerator.java
+++ b/arthur-impl/src/main/java/org/apache/geronimo/arthur/impl/nativeimage/generator/ConfigurationGenerator.java
@@ -186,31 +186,7 @@
         final Iterator<ClassReflectionModel> modelIterator = classReflectionModels.iterator();
         final ClassReflectionModel model = modelIterator.next();
         while (modelIterator.hasNext()) {
-            final ClassReflectionModel next = modelIterator.next();
-            if (next.getAllDeclaredClasses()) {
-                model.setAllDeclaredClasses(true);
-            }
-            if (next.getAllDeclaredFields()) {
-                model.setAllDeclaredFields(true);
-            }
-            if (next.getAllDeclaredConstructors()) {
-                model.setAllDeclaredConstructors(true);
-            }
-            if (next.getAllDeclaredMethods()) {
-                model.setAllDeclaredMethods(true);
-            }
-            if (next.getAllPublicMethods()) {
-                model.setAllPublicMethods(true);
-            }
-            if (next.getAllPublicFields()) {
-                model.setAllPublicFields(true);
-            }
-            if (next.getAllPublicConstructors()) {
-                model.setAllPublicConstructors(true);
-            }
-            if (next.getAllPublicClasses()) {
-                model.setAllPublicClasses(true);
-            }
+            model.merge(modelIterator.next());
         }
         return model;
     }
diff --git a/arthur-impl/src/main/java/org/apache/geronimo/arthur/impl/nativeimage/generator/DefautContext.java b/arthur-impl/src/main/java/org/apache/geronimo/arthur/impl/nativeimage/generator/DefautContext.java
index 6cdbca0..fdbb9d9 100644
--- a/arthur-impl/src/main/java/org/apache/geronimo/arthur/impl/nativeimage/generator/DefautContext.java
+++ b/arthur-impl/src/main/java/org/apache/geronimo/arthur/impl/nativeimage/generator/DefautContext.java
@@ -85,8 +85,17 @@
 
     @Override
     public void register(final ClassReflectionModel classReflectionModel) {
-        reflections.removeIf(it -> Objects.equals(classReflectionModel.getName(), it.getName()));
-        reflections.add(classReflectionModel);
+        reflections.stream()
+                .filter(it -> Objects.equals(classReflectionModel.getName(), it.getName()))
+                .findFirst()
+                .map(it -> {
+                    it.merge(classReflectionModel);
+                    return it;
+                })
+                .orElseGet(() -> {
+                    reflections.add(classReflectionModel);
+                    return classReflectionModel;
+                });
         modified = true;
     }
 
@@ -98,9 +107,14 @@
 
     @Override
     public void register(final ResourceBundleModel resourceBundleModel) {
-        bundles.removeIf(it -> Objects.equals(it.getName(), resourceBundleModel.getName()));
-        bundles.add(resourceBundleModel);
-        modified = true;
+        bundles.stream()
+                .filter(it -> Objects.equals(resourceBundleModel.getName(), it.getName()))
+                .findFirst()
+                .orElseGet(() -> {
+                    modified = true;
+                    bundles.add(resourceBundleModel);
+                    return resourceBundleModel;
+                });
     }
 
     @Override
diff --git a/arthur-spi/src/main/java/org/apache/geronimo/arthur/spi/model/ClassReflectionModel.java b/arthur-spi/src/main/java/org/apache/geronimo/arthur/spi/model/ClassReflectionModel.java
index 7a064ac..81ff279 100644
--- a/arthur-spi/src/main/java/org/apache/geronimo/arthur/spi/model/ClassReflectionModel.java
+++ b/arthur-spi/src/main/java/org/apache/geronimo/arthur/spi/model/ClassReflectionModel.java
@@ -16,11 +16,15 @@
  */
 package org.apache.geronimo.arthur.spi.model;
 
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
 import java.util.Collection;
 
-import lombok.Data;
-
 @Data
+@NoArgsConstructor
+@AllArgsConstructor
 public class ClassReflectionModel {
     private String name;
     private Boolean allDeclaredConstructors;
@@ -34,13 +38,60 @@
     private Collection<FieldReflectionModel> fields;
     private Collection<MethodReflectionModel> methods;
 
+    public ClassReflectionModel allPublic(final String name) {
+        return new ClassReflectionModel(name, null, true, null, true, null, null, null, true, null, null);
+    }
+
+    public ClassReflectionModel allPublicConstructors(final String name) {
+        return new ClassReflectionModel(name, null, true, null, null, null, null, null, null, null, null);
+    }
+
+    public ClassReflectionModel allDeclaredConstructors(final String name) {
+        return new ClassReflectionModel(name, null, null, true, null, null, null, null, null, null, null);
+    }
+
+    public ClassReflectionModel allDeclared(final String name) {
+        return new ClassReflectionModel(name, true, null, true, null, null, null, true, null, null, null);
+    }
+
+    public void merge(final ClassReflectionModel other) {
+        if (other.getAllDeclaredClasses() != null && other.getAllDeclaredClasses()) {
+            setAllDeclaredClasses(true);
+        }
+        if (other.getAllDeclaredFields() != null && other.getAllDeclaredFields()) {
+            setAllDeclaredFields(true);
+        }
+        if (other.getAllDeclaredConstructors() != null && other.getAllDeclaredConstructors()) {
+            setAllDeclaredConstructors(true);
+        }
+        if (other.getAllDeclaredMethods() != null && other.getAllDeclaredMethods()) {
+            setAllDeclaredMethods(true);
+        }
+        if (other.getAllPublicMethods() != null && other.getAllPublicMethods()) {
+            setAllPublicMethods(true);
+        }
+        if (other.getAllPublicFields() != null && other.getAllPublicFields()) {
+            setAllPublicFields(true);
+        }
+        if (other.getAllPublicConstructors() != null && other.getAllPublicConstructors()) {
+            setAllPublicConstructors(true);
+        }
+        if (other.getAllPublicClasses() != null && other.getAllPublicClasses()) {
+            setAllPublicClasses(true);
+        }
+    }
+
     @Data
+    @NoArgsConstructor
+    @AllArgsConstructor
     public static class FieldReflectionModel {
         private String name;
         private Boolean allowWrite;
     }
 
     @Data
+    @NoArgsConstructor
+    @AllArgsConstructor
     public static class MethodReflectionModel {
         private String name;
         private Collection<Class<?>> parameterTypes;
diff --git a/arthur-spi/src/main/java/org/apache/geronimo/arthur/spi/model/DynamicProxyModel.java b/arthur-spi/src/main/java/org/apache/geronimo/arthur/spi/model/DynamicProxyModel.java
index 661a4f0..9c0c7d9 100644
--- a/arthur-spi/src/main/java/org/apache/geronimo/arthur/spi/model/DynamicProxyModel.java
+++ b/arthur-spi/src/main/java/org/apache/geronimo/arthur/spi/model/DynamicProxyModel.java
@@ -16,11 +16,15 @@
  */
 package org.apache.geronimo.arthur.spi.model;
 
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
 import java.util.Collection;
 
-import lombok.Data;
-
 @Data
+@NoArgsConstructor
+@AllArgsConstructor
 public class DynamicProxyModel {
     private Collection<String> classes;
 }
diff --git a/arthur-spi/src/main/java/org/apache/geronimo/arthur/spi/model/ResourceBundleModel.java b/arthur-spi/src/main/java/org/apache/geronimo/arthur/spi/model/ResourceBundleModel.java
index 6c1c943..1a32723 100644
--- a/arthur-spi/src/main/java/org/apache/geronimo/arthur/spi/model/ResourceBundleModel.java
+++ b/arthur-spi/src/main/java/org/apache/geronimo/arthur/spi/model/ResourceBundleModel.java
@@ -16,9 +16,13 @@
  */
 package org.apache.geronimo.arthur.spi.model;
 
+import lombok.AllArgsConstructor;
 import lombok.Data;
+import lombok.NoArgsConstructor;
 
 @Data
+@NoArgsConstructor
+@AllArgsConstructor
 public class ResourceBundleModel {
     private String name;
 }
diff --git a/arthur-spi/src/main/java/org/apache/geronimo/arthur/spi/model/ResourceModel.java b/arthur-spi/src/main/java/org/apache/geronimo/arthur/spi/model/ResourceModel.java
index 549a4d1..8e9bd27 100644
--- a/arthur-spi/src/main/java/org/apache/geronimo/arthur/spi/model/ResourceModel.java
+++ b/arthur-spi/src/main/java/org/apache/geronimo/arthur/spi/model/ResourceModel.java
@@ -16,9 +16,13 @@
  */
 package org.apache.geronimo.arthur.spi.model;
 
+import lombok.AllArgsConstructor;
 import lombok.Data;
+import lombok.NoArgsConstructor;
 
 @Data
+@NoArgsConstructor
+@AllArgsConstructor
 public class ResourceModel {
     private String pattern;
 }
diff --git a/arthur-spi/src/main/java/org/apache/geronimo/arthur/spi/model/ResourcesModel.java b/arthur-spi/src/main/java/org/apache/geronimo/arthur/spi/model/ResourcesModel.java
index 73a137f..0ca3e50 100644
--- a/arthur-spi/src/main/java/org/apache/geronimo/arthur/spi/model/ResourcesModel.java
+++ b/arthur-spi/src/main/java/org/apache/geronimo/arthur/spi/model/ResourcesModel.java
@@ -16,11 +16,15 @@
  */
 package org.apache.geronimo.arthur.spi.model;
 
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
 import java.util.Collection;
 
-import lombok.Data;
-
 @Data
+@NoArgsConstructor
+@AllArgsConstructor
 public class ResourcesModel {
     private Collection<ResourceModel> resources;
     private Collection<ResourceBundleModel> bundles;
diff --git a/documentation/src/content/knights.adoc b/documentation/src/content/knights.adoc
index 7e42e78..a787c72 100644
--- a/documentation/src/content/knights.adoc
+++ b/documentation/src/content/knights.adoc
@@ -25,6 +25,8 @@
 - link:winegrower-knight.html[Winegrower]: Apache winegrower (Cloud OSGi runtime) support.
 - link:openwebbeans-knight.html[OpenWebBeans]: Apache OpenWebBeans (CDI SE runtime) support.
 - link:slf4j-knight.html[SLF4J]: SLF4J (JUL) integration.
+- derby-knight: Apache Derby integration.
+- openjpa-knight: Apache OpenJPA integration.
 
 == Configure a Knight in Arthur Maven plugin
 
diff --git a/integration-test/src/test/java/org/apache/geronimo/arthur/integrationtests/MavenTest.java b/integration-test/src/test/java/org/apache/geronimo/arthur/integrationtests/MavenTest.java
index 8b7c780..9006729 100644
--- a/integration-test/src/test/java/org/apache/geronimo/arthur/integrationtests/MavenTest.java
+++ b/integration-test/src/test/java/org/apache/geronimo/arthur/integrationtests/MavenTest.java
@@ -55,6 +55,14 @@
     void scr() {}
 
     @Test
+    @Spec(expectedOutput = "" +
+            "[main] INFO org.apache.geronimo.arthur.integrationtests.OpenJPAMain -" +
+            " findbyid => root:id=10000,name=root_1,children=[child:id=10001,name=child_2, child:id=10000,name=child_1]\n" +
+            "[main] INFO org.apache.geronimo.arthur.integrationtests.OpenJPAMain -" +
+            " criteria builder => root:id=10000,name=root_1,children=[child:id=10001,name=child_2, child:id=10000,name=child_1]")
+    void openjpa() {}
+
+    @Test
     @Spec(expectedOutput = "pong", forwardedExecutionSystemProperties = {
             "MavenTest.jsch.port", "java.library.path", "javax.net.ssl.trustStore"
     })
diff --git a/integration-test/src/test/resources/integration-tests/openjpa/pom.xml b/integration-test/src/test/resources/integration-tests/openjpa/pom.xml
new file mode 100644
index 0000000..028ec9e
--- /dev/null
+++ b/integration-test/src/test/resources/integration-tests/openjpa/pom.xml
@@ -0,0 +1,154 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+    Licensed to the Apache Software Foundation (ASF) under one or more
+    contributor license agreements.  See the NOTICE file distributed with
+    this work for additional information regarding copyright ownership.
+    The ASF licenses this file to You under the Apache License, Version 2.0
+    (the "License"); you may not use this file except in compliance with
+    the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="
+            http://maven.apache.org/POM/4.0.0
+            http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <!--parent>
+    <groupId>org.apache</groupId>
+    <artifactId>apache</artifactId>
+    <version>21</version>
+  </parent-->
+
+  <parent>
+    <artifactId>knights</artifactId>
+    <groupId>org.apache.geronimo.arthur.knights</groupId>
+    <version>1.0.3-SNAPSHOT</version>
+  </parent>
+  <properties>
+    <!-- main deps -->
+    <slf4j.version>1.7.28</slf4j.version>
+    <ziplock.version>8.0.0</ziplock.version>
+
+    <!-- knights -->
+    <jsch.version>0.1.55</jsch.version>
+    <graalvm.version>20.3.0</graalvm.version>
+    <winegrower.version>1.0.0</winegrower.version>
+
+    <!-- plugin versions/confs -->
+    <maven-compiler-plugin.version>3.8.1</maven-compiler-plugin.version>
+    <maven.compiler.source>8</maven.compiler.source>
+    <maven.compiler.target>8</maven.compiler.target>
+
+    <!-- jar vars -->
+    <geronimo-arthur.shortname>${project.artifactId}</geronimo-arthur.shortname>
+    <geronimo-arthur.Automatic-Module-Name>${project.groupId}.${geronimo-arthur.shortname}
+    </geronimo-arthur.Automatic-Module-Name>
+    <junit.version>5.7.0</junit.version>
+
+    <openjpa.version>3.1.2</openjpa.version>
+    <derby.version>10.14.2.0</derby.version>
+  </properties>
+
+  <modelVersion>4.0.0</modelVersion>
+
+  <groupId>org.apache.geronimo.arthur.integrationtests</groupId>
+  <artifactId>openjpa</artifactId>
+  <!--<version>1.0.0-SNAPSHOT</version>-->
+  <name>Arthur :: Integration Tests :: OpenJPA</name>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.apache.openjpa</groupId>
+      <artifactId>openjpa</artifactId>
+      <version>${openjpa.version}</version>
+    </dependency>
+    <dependency> <!-- for hikari -->
+      <groupId>org.slf4j</groupId>
+      <artifactId>slf4j-api</artifactId>
+      <version>${slf4j.version}</version>
+      <scope>compile</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.slf4j</groupId>
+      <artifactId>slf4j-simple</artifactId>
+      <version>${slf4j.version}</version>
+      <scope>compile</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.commons</groupId>
+      <artifactId>commons-dbcp2</artifactId>
+      <version>2.8.0</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.derby</groupId>
+      <artifactId>derbytools</artifactId>
+      <version>${derby.version}</version>
+      <scope>system</scope>
+      <systemPath>/opt/rmannibucau/dev/derby-10.14/jars/sane/derbytools.jar</systemPath>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.derby</groupId>
+      <artifactId>derby</artifactId>
+      <version>${derby.version}</version>
+      <scope>system</scope>
+      <systemPath>/opt/rmannibucau/dev/derby-10.14/jars/sane/derby.jar</systemPath>
+    </dependency>
+  </dependencies>
+
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.openjpa</groupId>
+        <artifactId>openjpa-maven-plugin</artifactId>
+        <version>${openjpa.version}</version>
+        <executions>
+          <execution>
+            <id>enhancer</id>
+            <phase>compile</phase>
+            <goals>
+              <goal>enhance</goal>
+            </goals>
+          </execution>
+        </executions>
+        <configuration>
+          <includes>org/apache/geronimo/arthur/integrationtests/entities/*.class</includes>
+          <sqlAction>build</sqlAction>
+          <toolProperties>
+            <MappingDefaults>jpa(ForeignKeyDeleteAction=restrict,JoinForeignKeyDeleteAction=restrict)</MappingDefaults>
+            <MetaDataFactory>jpa</MetaDataFactory>
+          </toolProperties>
+        </configuration>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-compiler-plugin</artifactId>
+        <version>${maven-compiler-plugin.version}</version>
+        <configuration>
+          <source>${maven.compiler.source}</source>
+          <target>${maven.compiler.target}</target>
+        </configuration>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.geronimo.arthur</groupId>
+        <artifactId>arthur-maven-plugin</artifactId>
+        <version>${project.version}</version>
+        <configuration>
+          <main>org.apache.geronimo.arthur.integrationtests.OpenJPAMain</main>
+          <graalExtensions>
+            <graalExtension>derby</graalExtension>
+            <graalExtension>openjpa</graalExtension>
+          </graalExtensions>
+          <!-- avoid to conflict with host cache since we mount the local m2 to speed up the execution -->
+          <graalCacheGav>org.apache.geronimo.arthur.cache:graal-integrationtests</graalCacheGav>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+</project>
diff --git a/integration-test/src/test/resources/integration-tests/openjpa/src/main/java/org/apache/geronimo/arthur/integrationtests/OpenJPAMain.java b/integration-test/src/test/resources/integration-tests/openjpa/src/main/java/org/apache/geronimo/arthur/integrationtests/OpenJPAMain.java
new file mode 100644
index 0000000..c33a1dc
--- /dev/null
+++ b/integration-test/src/test/resources/integration-tests/openjpa/src/main/java/org/apache/geronimo/arthur/integrationtests/OpenJPAMain.java
@@ -0,0 +1,222 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.geronimo.arthur.integrationtests;
+
+import org.apache.commons.dbcp2.BasicDataSource;
+import org.apache.derby.jdbc.EmbeddedDriver;
+import org.apache.geronimo.arthur.integrationtests.entities.Child;
+import org.apache.geronimo.arthur.integrationtests.entities.Root;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.persistence.EntityManager;
+import javax.persistence.EntityManagerFactory;
+import javax.persistence.EntityTransaction;
+import javax.persistence.SharedCacheMode;
+import javax.persistence.ValidationMode;
+import javax.persistence.criteria.CriteriaBuilder;
+import javax.persistence.criteria.CriteriaQuery;
+import javax.persistence.spi.ClassTransformer;
+import javax.persistence.spi.PersistenceProvider;
+import javax.persistence.spi.PersistenceUnitInfo;
+import javax.persistence.spi.PersistenceUnitTransactionType;
+import javax.sql.DataSource;
+import java.net.URL;
+import java.sql.DriverManager;
+import java.sql.SQLException;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import java.util.ServiceLoader;
+import java.util.UUID;
+
+import static java.util.Arrays.asList;
+import static java.util.Collections.emptyList;
+
+public final class OpenJPAMain {
+    private OpenJPAMain() {
+        // noop
+    }
+
+    /**
+     * [main] INFO org.apache.geronimo.arthur.integrationtests.OpenJPAMain - findbyid => root:id=10000,name=root_1,children=[child:id=10001,name=child_2, child:id=10000,name=child_1]
+     * [main] INFO org.apache.geronimo.arthur.integrationtests.OpenJPAMain - criteria builder => root:id=10000,name=root_1,children=[child:id=10001,name=child_2, child:id=10000,name=child_1]
+     */
+    public static void main(final String... args) throws SQLException {
+        setIfMissing("org.slf4j.simpleLogger.logFile", "System.out");
+        setIfMissing("org.slf4j.simpleLogger.defaultLogLevel", "WARN");
+        setIfMissing("org.slf4j.simpleLogger.log.org.apache.geronimo.arthur.integrationtests", "INFO");
+        setIfMissing("derby.stream.error.file", "target/derby_" + UUID.randomUUID() + ".log");
+
+        final BasicDataSource dataSource = createDataSource();
+        final Map<String, Object> map = new HashMap<>();
+        final Properties properties = new Properties();
+        properties.setProperty("javax.persistence.schema-generation.database.action", "drop-and-create");
+        properties.setProperty("openjpa.Log", "DefaultLevel=WARN, Runtime=WARN, Tool=WARN");
+        properties.setProperty("openjpa.Sequence", "class-table(Table=SEQUENCES, Increment=20, InitialValue=10000)");
+        final EntityManagerFactory factory = ServiceLoader.load(PersistenceProvider.class).iterator().next()
+                // use no xml option for now
+                .createContainerEntityManagerFactory(newInfo(dataSource, properties), map);
+        final Logger logger = LoggerFactory.getLogger(OpenJPAMain.class);
+        try {
+            final long rootId = createGraph(factory.createEntityManager());
+
+            final EntityManager findByIdEm = factory.createEntityManager();
+            logger.info("findbyid => " + findByIdEm.find(Root.class, rootId).toString());
+            findByIdEm.close();
+
+            final EntityManager criteriaBuilderEm = factory.createEntityManager();
+            final CriteriaBuilder cb = criteriaBuilderEm.getCriteriaBuilder();
+            final CriteriaQuery<Root> query = cb.createQuery(Root.class);
+            final javax.persistence.criteria.Root<Root> from = query.from(Root.class);
+            final CriteriaQuery<Root> criteriaQuery = query.select(from).where(cb.equal(from.get("id"), rootId));
+            logger.info("criteria builder => " + criteriaBuilderEm.createQuery(criteriaQuery).getSingleResult());
+            criteriaBuilderEm.close();
+        } finally {
+            factory.close();
+            dataSource.close();
+        }
+    }
+
+    private static long createGraph(final EntityManager entityManager) {
+        final EntityTransaction transaction = entityManager.getTransaction();
+        transaction.begin();
+
+        final Root root = new Root();
+        root.setName("root_1");
+        entityManager.persist(root);
+
+        final Child child1 = new Child();
+        child1.setName("child_1");
+        child1.setRoot(root);
+        entityManager.persist(child1);
+
+        final Child child2 = new Child();
+        child2.setName("child_2");
+        child2.setRoot(root);
+        entityManager.persist(child2);
+
+        transaction.commit();
+        entityManager.close();
+        return root.getId();
+    }
+
+    private static BasicDataSource createDataSource() throws SQLException {
+        DriverManager.registerDriver(new EmbeddedDriver());
+        final BasicDataSource dataSource = new BasicDataSource();
+        dataSource.setDriverClassName("org.apache.derby.jdbc.EmbeddedDriver");
+        dataSource.setUrl("jdbc:derby:target/arthur_" + UUID.randomUUID().toString().replace('-', '_') + ";create=true");
+        dataSource.setUsername("sa");
+        dataSource.setPassword("");
+        dataSource.setMinIdle(1);
+        return dataSource;
+    }
+
+    private static PersistenceUnitInfo newInfo(final DataSource dataSource, final Properties properties) {
+        return new PersistenceUnitInfo() {
+            @Override
+            public String getPersistenceUnitName() {
+                return "arthur";
+            }
+
+            @Override
+            public String getPersistenceProviderClassName() {
+                return "org.apache.openjpa.persistence.PersistenceProviderImpl";
+            }
+
+            @Override
+            public PersistenceUnitTransactionType getTransactionType() {
+                return PersistenceUnitTransactionType.RESOURCE_LOCAL;
+            }
+
+            @Override
+            public DataSource getJtaDataSource() {
+                return dataSource;
+            }
+
+            @Override
+            public DataSource getNonJtaDataSource() {
+                return dataSource;
+            }
+
+            @Override
+            public List<String> getMappingFileNames() {
+                return emptyList();
+            }
+
+            @Override
+            public List<URL> getJarFileUrls() {
+                return emptyList();
+            }
+
+            @Override
+            public URL getPersistenceUnitRootUrl() {
+                return null;
+            }
+
+            @Override
+            public List<String> getManagedClassNames() {
+                return asList(Root.class.getName(), Child.class.getName());
+            }
+
+            @Override
+            public boolean excludeUnlistedClasses() {
+                return true;
+            }
+
+            @Override
+            public SharedCacheMode getSharedCacheMode() {
+                return SharedCacheMode.UNSPECIFIED;
+            }
+
+            @Override
+            public ValidationMode getValidationMode() {
+                return ValidationMode.AUTO;
+            }
+
+            @Override
+            public Properties getProperties() {
+                return properties;
+            }
+
+            @Override
+            public String getPersistenceXMLSchemaVersion() {
+                return "2.0";
+            }
+
+            @Override
+            public ClassLoader getClassLoader() {
+                return Thread.currentThread().getContextClassLoader();
+            }
+
+            @Override
+            public void addTransformer(final ClassTransformer transformer) {
+                // no-op
+            }
+
+            @Override
+            public ClassLoader getNewTempClassLoader() {
+                return getClassLoader();
+            }
+        };
+    }
+
+    private static void setIfMissing(final String key, final String value) {
+        System.setProperty(key, System.getProperty(key, value));
+    }
+}
diff --git a/integration-test/src/test/resources/integration-tests/openjpa/src/main/java/org/apache/geronimo/arthur/integrationtests/entities/Child.java b/integration-test/src/test/resources/integration-tests/openjpa/src/main/java/org/apache/geronimo/arthur/integrationtests/entities/Child.java
new file mode 100644
index 0000000..55f4254
--- /dev/null
+++ b/integration-test/src/test/resources/integration-tests/openjpa/src/main/java/org/apache/geronimo/arthur/integrationtests/entities/Child.java
@@ -0,0 +1,76 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.geronimo.arthur.integrationtests.entities;
+
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.Id;
+import javax.persistence.ManyToOne;
+import java.util.Objects;
+
+@Entity
+public class Child {
+    @Id
+    @GeneratedValue
+    private long id;
+    private String name;
+
+    @ManyToOne
+    private Root root;
+
+    public long getId() {
+        return id;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(final String name) {
+        this.name = name;
+    }
+
+    public Root getRoot() {
+        return root;
+    }
+
+    public void setRoot(final Root root) {
+        this.root = root;
+    }
+
+    @Override
+    public String toString() {
+        return "child:id=" + id + ",name=" + name;
+    }
+
+    @Override
+    public boolean equals(final Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (o == null || getClass() != o.getClass()) {
+            return false;
+        }
+        final Child child = Child.class.cast(o);
+        return id == child.id;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(id);
+    }
+}
diff --git a/integration-test/src/test/resources/integration-tests/openjpa/src/main/java/org/apache/geronimo/arthur/integrationtests/entities/Root.java b/integration-test/src/test/resources/integration-tests/openjpa/src/main/java/org/apache/geronimo/arthur/integrationtests/entities/Root.java
new file mode 100644
index 0000000..4af11e6
--- /dev/null
+++ b/integration-test/src/test/resources/integration-tests/openjpa/src/main/java/org/apache/geronimo/arthur/integrationtests/entities/Root.java
@@ -0,0 +1,79 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.geronimo.arthur.integrationtests.entities;
+
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.Id;
+import javax.persistence.OneToMany;
+import javax.persistence.OrderBy;
+import java.util.List;
+import java.util.Objects;
+
+@Entity
+public class Root {
+    @Id
+    @GeneratedValue
+    private long id;
+    private String name;
+
+    @OrderBy("name DESC")
+    @OneToMany(mappedBy = "root")
+    private List<Child> children;
+
+    public long getId() {
+        return id;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(final String name) {
+        this.name = name;
+    }
+
+    public List<Child> getChildren() {
+        return children;
+    }
+
+    public void setChildren(final List<Child> children) {
+        this.children = children;
+    }
+
+    @Override
+    public String toString() {
+        return "root:id=" + id + ",name=" + name + ",children=" + children;
+    }
+
+    @Override
+    public boolean equals(final Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (o == null || getClass() != o.getClass()) {
+            return false;
+        }
+        final Root child = Root.class.cast(o);
+        return id == child.id;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(id);
+    }
+}
diff --git a/knights/derby-knight/pom.xml b/knights/derby-knight/pom.xml
new file mode 100644
index 0000000..d4233f8
--- /dev/null
+++ b/knights/derby-knight/pom.xml
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+    Licensed to the Apache Software Foundation (ASF) under one or more
+    contributor license agreements.  See the NOTICE file distributed with
+    this work for additional information regarding copyright ownership.
+    The ASF licenses this file to You under the Apache License, Version 2.0
+    (the "License"); you may not use this file except in compliance with
+    the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <parent>
+    <artifactId>knights</artifactId>
+    <groupId>org.apache.geronimo.arthur.knights</groupId>
+    <version>1.0.3-SNAPSHOT</version>
+  </parent>
+  <modelVersion>4.0.0</modelVersion>
+
+  <artifactId>derby-knight</artifactId>
+  <name>Arthur :: Knights :: Derby</name>
+
+  <properties>
+    <geronimo-arthur.shortname>knight.derby</geronimo-arthur.shortname>
+  </properties>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.slf4j</groupId>
+      <artifactId>slf4j-api</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.geronimo.arthur</groupId>
+      <artifactId>arthur-spi</artifactId>
+    </dependency>
+
+    <dependency>
+      <groupId>org.apache.geronimo.arthur</groupId>
+      <artifactId>arthur-impl</artifactId>
+    </dependency>
+  </dependencies>
+</project>
diff --git a/knights/derby-knight/src/main/java/org/apache/geronimo/arthur/knight/derby/DerbyExtension.java b/knights/derby-knight/src/main/java/org/apache/geronimo/arthur/knight/derby/DerbyExtension.java
new file mode 100644
index 0000000..cc7b272
--- /dev/null
+++ b/knights/derby-knight/src/main/java/org/apache/geronimo/arthur/knight/derby/DerbyExtension.java
@@ -0,0 +1,402 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.geronimo.arthur.knight.derby;
+
+import org.apache.geronimo.arthur.spi.ArthurExtension;
+import org.apache.geronimo.arthur.spi.model.ClassReflectionModel;
+import org.apache.geronimo.arthur.spi.model.ResourceModel;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.sql.Driver;
+import java.util.Objects;
+import java.util.Properties;
+import java.util.stream.Stream;
+
+import static java.util.Optional.ofNullable;
+
+public class DerbyExtension implements ArthurExtension {
+    @Override
+    public void execute(final Context context) {
+        registerProperties(context);
+        tryToRegisterSPI(context);
+        context.findImplementations(Driver.class)
+                .forEach(it -> registerClass(context, it.getName()));
+
+        // extraDBMSclasses.properties + StoredFormatIds + ClassName + RegisteredFormatIds
+        Stream.of(
+                "org.apache.derby.catalog.GetProcedureColumns",
+                "org.apache.derby.catalog.Java5SystemProcedures",
+                "org.apache.derby.catalog.SystemProcedures",
+                "org.apache.derby.catalog.TriggerNewTransitionRows",
+                "org.apache.derby.catalog.TriggerOldTransitionRows",
+                "org.apache.derby.catalog.UUID",
+                "org.apache.derby.catalog.types.AggregateAliasInfo",
+                "org.apache.derby.catalog.types.BitTypeIdImpl",
+                "org.apache.derby.catalog.types.BooleanTypeIdImpl",
+                "org.apache.derby.catalog.types.CharTypeIdImpl",
+                "org.apache.derby.catalog.types.ClassAliasInfo",
+                "org.apache.derby.catalog.types.DecimalTypeIdImpl",
+                "org.apache.derby.catalog.types.DefaultInfoImpl",
+                "org.apache.derby.catalog.types.DoubleTypeIdImpl",
+                "org.apache.derby.catalog.types.IndexDescriptorImpl",
+                "org.apache.derby.catalog.types.IntTypeIdImpl",
+                "org.apache.derby.catalog.types.LongintTypeIdImpl",
+                "org.apache.derby.catalog.types.LongvarbitTypeIdImpl",
+                "org.apache.derby.catalog.types.LongvarcharTypeIdImpl",
+                "org.apache.derby.catalog.types.MethodAliasInfo",
+                "org.apache.derby.catalog.types.NationalCharTypeIdImpl",
+                "org.apache.derby.catalog.types.NationalLongVarcharTypeIdImpl",
+                "org.apache.derby.catalog.types.NationalVarcharTypeIdImpl",
+                "org.apache.derby.catalog.types.RealTypeIdImpl",
+                "org.apache.derby.catalog.types.RefTypeIdImpl",
+                "org.apache.derby.catalog.types.ReferencedColumnsDescriptorImpl",
+                "org.apache.derby.catalog.types.RoutineAliasInfo",
+                "org.apache.derby.catalog.types.RowMultiSetImpl",
+                "org.apache.derby.catalog.types.SmallintTypeIdImpl",
+                "org.apache.derby.catalog.types.StatisticsImpl",
+                "org.apache.derby.catalog.types.SynonymAliasInfo",
+                "org.apache.derby.catalog.types.TinyintTypeIdImpl",
+                "org.apache.derby.catalog.types.TypeDescriptorImpl",
+                "org.apache.derby.catalog.types.TypesImplInstanceGetter",
+                "org.apache.derby.catalog.types.UDTAliasInfo",
+                "org.apache.derby.catalog.types.UserAggregateAliasInfo",
+                "org.apache.derby.catalog.types.UserDefinedTypeIdImpl",
+                "org.apache.derby.catalog.types.VarbitTypeIdImpl",
+                "org.apache.derby.catalog.types.VarcharTypeIdImpl",
+                "org.apache.derby.catalog.types.WorkUnitAliasInfo",
+                "org.apache.derby.diag.ContainedRoles",
+                "org.apache.derby.diag.ErrorLogReader",
+                "org.apache.derby.diag.ErrorMessages",
+                "org.apache.derby.diag.LockTable",
+                "org.apache.derby.diag.SpaceTable",
+                "org.apache.derby.diag.StatementCache",
+                "org.apache.derby.diag.StatementDuration",
+                "org.apache.derby.diag.TransactionTable",
+                "org.apache.derby.iapi.db.ConsistencyChecker",
+                "org.apache.derby.iapi.db.Factory",
+                "org.apache.derby.iapi.db.OptimizerTrace",
+                "org.apache.derby.iapi.db.PropertyInfo",
+                "org.apache.derby.iapi.error.StandardException",
+                "org.apache.derby.iapi.error.ThreadDump",
+                "org.apache.derby.iapi.services.cache.ClassSizeCatalogImpl",
+                "org.apache.derby.iapi.services.context.Context",
+                "org.apache.derby.iapi.services.diag.DiagnosticUtil",
+                "org.apache.derby.iapi.services.diag.DiagnosticableGeneric",
+                "org.apache.derby.iapi.services.io.FormatableArrayHolder",
+                "org.apache.derby.iapi.services.io.FormatableBitSet",
+                "org.apache.derby.iapi.services.io.FormatableHashtable",
+                "org.apache.derby.iapi.services.io.FormatableIntHolder",
+                "org.apache.derby.iapi.services.io.FormatableLongHolder",
+                "org.apache.derby.iapi.services.io.FormatableProperties",
+                "org.apache.derby.iapi.services.io.Storable",
+                "org.apache.derby.iapi.services.io.StoredFormatIds",
+                "org.apache.derby.iapi.services.loader.GeneratedByteCode",
+                "org.apache.derby.iapi.services.loader.GeneratedClass",
+                "org.apache.derby.iapi.services.loader.GeneratedMethod",
+                "org.apache.derby.iapi.sql.Activation",
+                "org.apache.derby.iapi.sql.LanguageFactory",
+                "org.apache.derby.iapi.sql.ParameterValueSet",
+                "org.apache.derby.iapi.sql.ParameterValueSetFactory",
+                "org.apache.derby.iapi.sql.ResultSet",
+                "org.apache.derby.iapi.sql.Row",
+                "org.apache.derby.iapi.sql.conn.Authorizer",
+                "org.apache.derby.iapi.sql.conn.LanguageConnectionContext",
+                "org.apache.derby.iapi.sql.dictionary.DataDictionary",
+                "org.apache.derby.iapi.sql.dictionary.IndexRowGenerator",
+                "org.apache.derby.iapi.sql.dictionary.TriggerDescriptor",
+                "org.apache.derby.iapi.sql.execute.ConstantAction",
+                "org.apache.derby.iapi.sql.execute.CursorResultSet",
+                "org.apache.derby.iapi.sql.execute.ExecIndexRow",
+                "org.apache.derby.iapi.sql.execute.ExecPreparedStatement",
+                "org.apache.derby.iapi.sql.execute.ExecRow",
+                "org.apache.derby.iapi.sql.execute.ExecRowBuilder",
+                "org.apache.derby.iapi.sql.execute.ExecutionFactory",
+                "org.apache.derby.iapi.sql.execute.NoPutResultSet",
+                "org.apache.derby.iapi.sql.execute.ResultSetFactory",
+                "org.apache.derby.iapi.sql.execute.RowFactory",
+                "org.apache.derby.iapi.sql.execute.RunTimeStatistics",
+                "org.apache.derby.iapi.store.access.Qualifier",
+                "org.apache.derby.iapi.types.BitDataValue",
+                "org.apache.derby.iapi.types.BitTypeId",
+                "org.apache.derby.iapi.types.BooleanDataValue",
+                "org.apache.derby.iapi.types.BooleanTypeId",
+                "org.apache.derby.iapi.types.CharTypeId",
+                "org.apache.derby.iapi.types.ConcatableDataValue",
+                "org.apache.derby.iapi.types.DTSClassInfo",
+                "org.apache.derby.iapi.types.DataTypeDescriptor",
+                "org.apache.derby.iapi.types.DataValueDescriptor",
+                "org.apache.derby.iapi.types.DataValueFactory",
+                "org.apache.derby.iapi.types.DateTimeDataValue",
+                "org.apache.derby.iapi.types.DateTypeId",
+                "org.apache.derby.iapi.types.DecimalTypeId",
+                "org.apache.derby.iapi.types.DoubleTypeId",
+                "org.apache.derby.iapi.types.IntTypeId",
+                "org.apache.derby.iapi.types.JSQLType",
+                "org.apache.derby.iapi.types.LongintTypeId",
+                "org.apache.derby.iapi.types.LongvarbitTypeId",
+                "org.apache.derby.iapi.types.LongvarcharTypeId",
+                "org.apache.derby.iapi.types.NationalCharTypeId",
+                "org.apache.derby.iapi.types.NationalLongvarcharTypeId",
+                "org.apache.derby.iapi.types.NationalVarcharTypeId",
+                "org.apache.derby.iapi.types.NumberDataValue",
+                "org.apache.derby.iapi.types.RealTypeId",
+                "org.apache.derby.iapi.types.RefDataValue",
+                "org.apache.derby.iapi.types.RefTypeId",
+                "org.apache.derby.iapi.types.RowLocation",
+                "org.apache.derby.iapi.types.SQLLongint",
+                "org.apache.derby.iapi.types.SmallintTypeId",
+                "org.apache.derby.iapi.types.StringDataValue",
+                "org.apache.derby.iapi.types.TimeTypeId",
+                "org.apache.derby.iapi.types.TimestampTypeId",
+                "org.apache.derby.iapi.types.TinyintTypeId",
+                "org.apache.derby.iapi.types.UserDataValue",
+                "org.apache.derby.iapi.types.UserDefinedTypeId",
+                "org.apache.derby.iapi.types.UserDefinedTypeIdV2",
+                "org.apache.derby.iapi.types.UserDefinedTypeIdV3",
+                "org.apache.derby.iapi.types.UserType",
+                "org.apache.derby.iapi.types.VarbitTypeId",
+                "org.apache.derby.iapi.types.VarcharTypeId",
+                "org.apache.derby.iapi.types.VariableSizeDataValue",
+                "org.apache.derby.iapi.types.XML (implementation of",
+                "org.apache.derby.iapi.types.XMLDataValue",
+                "org.apache.derby.iapi.types.XMLDataValue)",
+                "org.apache.derby.impl.io.CPFile",
+                "org.apache.derby.impl.io.DirStorageFactory",
+                "org.apache.derby.impl.io.InputStreamFile",
+                "org.apache.derby.impl.io.JarDBFile",
+                "org.apache.derby.impl.io.URLFile",
+                "org.apache.derby.impl.io.VFMemoryStorageFactory",
+                "org.apache.derby.impl.jdbc.LOBStoredProcedure",
+                "org.apache.derby.impl.jdbc.SQLExceptionFactory",
+                "org.apache.derby.impl.jdbc.authentication.JNDIAuthenticationSchemeBase",
+                "org.apache.derby.impl.jdbc.authentication.JNDIAuthenticationService",
+                "org.apache.derby.impl.jdbc.authentication.LDAPAuthenticationSchemeImpl",
+                "org.apache.derby.impl.services.monitor.BaseMonitor",
+                "org.apache.derby.impl.services.monitor.FileMonitor",
+                "org.apache.derby.impl.services.stream.RollingFileStream",
+                "org.apache.derby.impl.services.stream.RollingFileStreamProvider",
+                "org.apache.derby.impl.services.uuid.BasicUUID",
+                "org.apache.derby.impl.services.uuid.BasicUUIDGetter",
+                "org.apache.derby.impl.sql.CursorInfo",
+                "org.apache.derby.impl.sql.CursorTableReference",
+                "org.apache.derby.impl.sql.GenericColumnDescriptor",
+                "org.apache.derby.impl.sql.GenericResultDescription",
+                "org.apache.derby.impl.sql.GenericStorablePreparedStatement",
+                "org.apache.derby.impl.sql.GenericTypeDescriptor",
+                "org.apache.derby.impl.sql.GenericTypeId",
+                "org.apache.derby.impl.sql.catalog.AliasDescriptorFinder",
+                "org.apache.derby.impl.sql.catalog.ColumnDescriptorFinder",
+                "org.apache.derby.impl.sql.catalog.ConglomerateDescriptorFinder",
+                "org.apache.derby.impl.sql.catalog.ConstraintDescriptorFinder",
+                "org.apache.derby.impl.sql.catalog.CoreDDFinderClassInfo",
+                "org.apache.derby.impl.sql.catalog.DD_AristotleVersion",
+                "org.apache.derby.impl.sql.catalog.DD_BuffyVersion",
+                "org.apache.derby.impl.sql.catalog.DD_DB2J72",
+                "org.apache.derby.impl.sql.catalog.DD_IvanovaVersion",
+                "org.apache.derby.impl.sql.catalog.DD_MulanVersion",
+                "org.apache.derby.impl.sql.catalog.DD_PlatoVersion",
+                "org.apache.derby.impl.sql.catalog.DD_SocratesVersion",
+                "org.apache.derby.impl.sql.catalog.DD_Version",
+                "org.apache.derby.impl.sql.catalog.DD_XenaVersion",
+                "org.apache.derby.impl.sql.catalog.DataDictionaryDescriptorFinder",
+                "org.apache.derby.impl.sql.catalog.DefaultDescriptorFinder",
+                "org.apache.derby.impl.sql.catalog.FileInfoFinder",
+                "org.apache.derby.impl.sql.catalog.IndexRowGeneratorImpl",
+                "org.apache.derby.impl.sql.catalog.OIDImpl",
+                "org.apache.derby.impl.sql.catalog.ParameterDescriptorImpl",
+                "org.apache.derby.impl.sql.catalog.RowListImpl",
+                "org.apache.derby.impl.sql.catalog.SPSDescriptorFinder",
+                "org.apache.derby.impl.sql.catalog.SchemaDescriptorFinder",
+                "org.apache.derby.impl.sql.catalog.SequenceDescriptorFinder",
+                "org.apache.derby.impl.sql.catalog.TableDescriptorFinder",
+                "org.apache.derby.impl.sql.catalog.TriggerDescriptor",
+                "org.apache.derby.impl.sql.catalog.TriggerDescriptorFinder",
+                "org.apache.derby.impl.sql.catalog.ViewDescriptorFinder",
+                "org.apache.derby.impl.sql.compile.MaxMinAggregateDefinition",
+                "org.apache.derby.impl.sql.compile.OptTraceViewer",
+                "org.apache.derby.impl.sql.compile.OptimizerTracer",
+                "org.apache.derby.impl.sql.compile.SumAvgAggregateDefinition",
+                "org.apache.derby.impl.sql.depend.DepClassInfo",
+                "org.apache.derby.impl.sql.execute.AggregatorInfo",
+                "org.apache.derby.impl.sql.execute.AggregatorInfoList",
+                "org.apache.derby.impl.sql.execute.AvgAggregator",
+                "org.apache.derby.impl.sql.execute.BaseActivation",
+                "org.apache.derby.impl.sql.execute.BaseExpressionActivation",
+                "org.apache.derby.impl.sql.execute.ColumnInfo",
+                "org.apache.derby.impl.sql.execute.ConstantActionActivation",
+                "org.apache.derby.impl.sql.execute.ConstraintInfo",
+                "org.apache.derby.impl.sql.execute.CountAggregator",
+                "org.apache.derby.impl.sql.execute.CurrentDatetime",
+                "org.apache.derby.impl.sql.execute.CursorActivation",
+                "org.apache.derby.impl.sql.execute.DeleteConstantAction",
+                "org.apache.derby.impl.sql.execute.FKInfo",
+                "org.apache.derby.impl.sql.execute.IndexColumnOrder",
+                "org.apache.derby.impl.sql.execute.InsertConstantAction",
+                "org.apache.derby.impl.sql.execute.MatchingClauseConstantAction",
+                "org.apache.derby.impl.sql.execute.MaxMinAggregator",
+                "org.apache.derby.impl.sql.execute.MergeConstantAction",
+                "org.apache.derby.impl.sql.execute.OrderableAggregator",
+                "org.apache.derby.impl.sql.execute.SavepointConstantAction",
+                "org.apache.derby.impl.sql.execute.StdDevPAggregator",
+                "org.apache.derby.impl.sql.execute.StdDevSAggregator",
+                "org.apache.derby.impl.sql.execute.SumAggregator",
+                "org.apache.derby.impl.sql.execute.TransactionConstantAction",
+                "org.apache.derby.impl.sql.execute.TriggerInfo",
+                "org.apache.derby.impl.sql.execute.UpdatableVTIConstantAction",
+                "org.apache.derby.impl.sql.execute.UpdateConstantAction",
+                "org.apache.derby.impl.sql.execute.UserDefinedAggregator",
+                "org.apache.derby.impl.sql.execute.VarPAggregator",
+                "org.apache.derby.impl.sql.execute.VarSAggregator",
+                "org.apache.derby.impl.store.access.ConglomerateDirectory",
+                "org.apache.derby.impl.store.access.PC_XenaVersion",
+                "org.apache.derby.impl.store.access.PropertyConglomerate",
+                "org.apache.derby.impl.store.access.StorableFormatId",
+                "org.apache.derby.impl.store.access.btree.BranchControlRow",
+                "org.apache.derby.impl.store.access.btree.LeafControlRow",
+                "org.apache.derby.impl.store.access.btree.index.B2I",
+                "org.apache.derby.impl.store.access.btree.index.B2IStaticCompiledInfo",
+                "org.apache.derby.impl.store.access.btree.index.B2IUndo",
+                "org.apache.derby.impl.store.access.btree.index.B2I_10_3",
+                "org.apache.derby.impl.store.access.btree.index.B2I_v10_2",
+                "org.apache.derby.impl.store.access.heap.Heap",
+                "org.apache.derby.impl.store.access.heap.HeapClassInfo",
+                "org.apache.derby.impl.store.access.heap.Heap_v10_2",
+                "org.apache.derby.impl.store.raw.data.AllocPage",
+                "org.apache.derby.impl.store.raw.data.AllocPageOperation",
+                "org.apache.derby.impl.store.raw.data.ChainAllocPageOperation",
+                "org.apache.derby.impl.store.raw.data.CompressSpacePageOperation",
+                "org.apache.derby.impl.store.raw.data.CompressSpacePageOperation10_2",
+                "org.apache.derby.impl.store.raw.data.ContainerOperation",
+                "org.apache.derby.impl.store.raw.data.ContainerUndoOperation",
+                "org.apache.derby.impl.store.raw.data.CopyRowsOperation",
+                "org.apache.derby.impl.store.raw.data.DeleteOperation",
+                "org.apache.derby.impl.store.raw.data.EncryptContainerOperation",
+                "org.apache.derby.impl.store.raw.data.EncryptContainerUndoOperation",
+                "org.apache.derby.impl.store.raw.data.FileContainer",
+                "org.apache.derby.impl.store.raw.data.InitPageOperation",
+                "org.apache.derby.impl.store.raw.data.InsertOperation",
+                "org.apache.derby.impl.store.raw.data.InvalidatePageOperation",
+                "org.apache.derby.impl.store.raw.data.LogicalUndoOperation",
+                "org.apache.derby.impl.store.raw.data.PhysicalUndoOperation",
+                "org.apache.derby.impl.store.raw.data.PurgeOperation",
+                "org.apache.derby.impl.store.raw.data.RemoveFileOperation",
+                "org.apache.derby.impl.store.raw.data.SetReservedSpaceOperation",
+                "org.apache.derby.impl.store.raw.data.StoredPage",
+                "org.apache.derby.impl.store.raw.data.StreamFileContainer",
+                "org.apache.derby.impl.store.raw.data.UpdateFieldOperation",
+                "org.apache.derby.impl.store.raw.data.UpdateOperation",
+                "org.apache.derby.impl.store.raw.log.CheckpointOperation",
+                "org.apache.derby.impl.store.raw.log.ChecksumOperation",
+                "org.apache.derby.impl.store.raw.log.LogCounter",
+                "org.apache.derby.impl.store.raw.log.LogRecord",
+                "org.apache.derby.impl.store.raw.log.LogToFile",
+                "org.apache.derby.impl.store.raw.xact.BeginXact",
+                "org.apache.derby.impl.store.raw.xact.EndXact",
+                "org.apache.derby.impl.store.raw.xact.GlobalXactId",
+                "org.apache.derby.impl.store.raw.xact.TransactionTable",
+                "org.apache.derby.impl.store.raw.xact.TransactionTableEntry",
+                "org.apache.derby.impl.store.raw.xact.XAXactId",
+                "org.apache.derby.impl.store.raw.xact.XactId",
+                "org.apache.derby.jdbc.BasicEmbeddedConnectionPoolDataSource40",
+                "org.apache.derby.jdbc.BasicEmbeddedDataSource40",
+                "org.apache.derby.jdbc.BasicEmbeddedXADataSource40",
+                "org.apache.derby.jdbc.EmbeddedConnectionPoolDataSource",
+                "org.apache.derby.jdbc.EmbeddedConnectionPoolDataSource40",
+                "org.apache.derby.jdbc.EmbeddedDataSource",
+                "org.apache.derby.jdbc.EmbeddedDataSource40",
+                "org.apache.derby.jdbc.EmbeddedDriver",
+                "org.apache.derby.jdbc.EmbeddedXADataSource",
+                "org.apache.derby.jdbc.EmbeddedXADataSource40",
+                "org.apache.derby.mbeans.Management",
+                "org.apache.derby.osgi.EmbeddedActivator",
+                "org.apache.derby.shared.common.sanity.ThreadDump",
+                "org.apache.derby.tools.sysinfo",
+                "org.apache.derby.vti.ForeignTableVTI",
+                "org.apache.derby.vti.StringColumnVTI",
+                "org.apache.derby.vti.UpdatableVTITemplate",
+                "org.apache.derby.vti.VTICosting",
+                "org.apache.derby.vti.VTIMetaDataTemplate",
+                "org.apache.derby.vti.XmlVTI"
+        ).distinct().forEach(it -> {
+            try {
+                registerClass(context, context.loadClass(it).getName());
+            } catch (final IllegalStateException | NoClassDefFoundError ise) {
+                // no-op
+            }
+        });
+        context.register(new ClassReflectionModel("org.apache.derby.iapi.services.context.ContextManager", null, null, null, null, null, null, null, null, null, null));
+        Stream.of(
+                "org.apache.derby.iapi.services.monitor.Monitor",
+                "org.apache.derby.iapi.services.context.ContextService"
+        ).forEach(it -> {
+            try {
+                context.initializeAtRunTime(context.loadClass(it).getName());
+            } catch (final IllegalStateException ise) {
+                // no-op
+            }
+        });
+    }
+
+    private void registerClass(final Context context, final String name) {
+        final ClassReflectionModel model = new ClassReflectionModel();
+        model.setName(name);
+        model.setAllPublicConstructors(true);
+        model.setAllDeclaredConstructors(true);
+        context.register(model);
+    }
+
+    private void tryToRegisterSPI(final Context context) {
+        final ClassLoader loader = Thread.currentThread().getContextClassLoader();
+        ofNullable(loader.getResourceAsStream("org/apache/derby/modules.properties"))
+                .map(res -> {
+                    final Properties properties = new Properties();
+                    try (final InputStream s = res) {
+                        properties.load(s);
+                    } catch (final IOException e) {
+                        throw new IllegalStateException(e);
+                    }
+                    return properties;
+                })
+                .ifPresent(props -> props.stringPropertyNames().stream()
+                        .map(props::getProperty)
+                        .flatMap(it -> Stream.of(it.split(",")))
+                        .map(String::trim)
+                        .filter(it -> !it.isEmpty())
+                        .map(it -> {
+                            try {
+                                return context.loadClass(it);
+                            } catch (final IllegalStateException ise) {
+                                return null;
+                            }
+                        })
+                        .filter(Objects::nonNull)
+                        .flatMap(context::findHierarchy)
+                        .forEach(it -> {
+                            final ClassReflectionModel model = new ClassReflectionModel();
+                            model.setName(it.getName());
+                            model.setAllDeclaredConstructors(true);
+                            context.register(model);
+                        }));
+    }
+
+    private void registerProperties(final Context context) {
+        final ResourceModel resourceModel = new ResourceModel();
+        resourceModel.setPattern("org\\/apache\\/derby\\/.+\\.properties");
+        context.register(resourceModel);
+    }
+}
diff --git a/knights/derby-knight/src/main/resources/META-INF/services/org.apache.geronimo.arthur.spi.ArthurExtension b/knights/derby-knight/src/main/resources/META-INF/services/org.apache.geronimo.arthur.spi.ArthurExtension
new file mode 100644
index 0000000..386e3a5
--- /dev/null
+++ b/knights/derby-knight/src/main/resources/META-INF/services/org.apache.geronimo.arthur.spi.ArthurExtension
@@ -0,0 +1 @@
+org.apache.geronimo.arthur.knight.derby.DerbyExtension
diff --git a/knights/openjpa-knight/pom.xml b/knights/openjpa-knight/pom.xml
new file mode 100644
index 0000000..6b6dae8
--- /dev/null
+++ b/knights/openjpa-knight/pom.xml
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+    Licensed to the Apache Software Foundation (ASF) under one or more
+    contributor license agreements.  See the NOTICE file distributed with
+    this work for additional information regarding copyright ownership.
+    The ASF licenses this file to You under the Apache License, Version 2.0
+    (the "License"); you may not use this file except in compliance with
+    the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <parent>
+    <artifactId>knights</artifactId>
+    <groupId>org.apache.geronimo.arthur.knights</groupId>
+    <version>1.0.3-SNAPSHOT</version>
+  </parent>
+  <modelVersion>4.0.0</modelVersion>
+
+  <artifactId>openjpa-knight</artifactId>
+  <name>Arthur :: Knights :: OpenJPA</name>
+
+  <properties>
+    <geronimo-arthur.shortname>knight.openjpa</geronimo-arthur.shortname>
+  </properties>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.slf4j</groupId>
+      <artifactId>slf4j-api</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.geronimo.arthur</groupId>
+      <artifactId>arthur-spi</artifactId>
+    </dependency>
+
+    <dependency>
+      <groupId>org.apache.openjpa</groupId>
+      <artifactId>openjpa</artifactId>
+      <version>3.1.2</version>
+    </dependency>
+
+    <dependency>
+      <groupId>org.apache.geronimo.arthur</groupId>
+      <artifactId>arthur-impl</artifactId>
+    </dependency>
+  </dependencies>
+</project>
diff --git a/knights/openjpa-knight/src/main/java/org/apache/geronimo/arthur/knight/openjpa/OpenJPAExtension.java b/knights/openjpa-knight/src/main/java/org/apache/geronimo/arthur/knight/openjpa/OpenJPAExtension.java
new file mode 100644
index 0000000..b13d699
--- /dev/null
+++ b/knights/openjpa-knight/src/main/java/org/apache/geronimo/arthur/knight/openjpa/OpenJPAExtension.java
@@ -0,0 +1,315 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.geronimo.arthur.knight.openjpa;
+
+import org.apache.geronimo.arthur.spi.ArthurExtension;
+import org.apache.geronimo.arthur.spi.model.ClassReflectionModel;
+import org.apache.geronimo.arthur.spi.model.ResourceBundleModel;
+import org.apache.geronimo.arthur.spi.model.ResourceModel;
+
+import javax.persistence.Embeddable;
+import javax.persistence.Entity;
+import javax.persistence.MappedSuperclass;
+import java.lang.reflect.Field;
+import java.util.Objects;
+import java.util.stream.Stream;
+
+public class OpenJPAExtension implements ArthurExtension {
+    @Override
+    public void execute(final Context context) {
+        registerJPAClasses(context);
+        registerSPI(context);
+        registerI18n(context);
+        registerDictionaryResources(context);
+        registerPrimitiveWrappers(context);
+        registerDBCP2IfPresent(context);
+    }
+
+    // see Options class (stringToObject method)
+    private void registerPrimitiveWrappers(final Context context) {
+        Stream.of(Boolean.class, Byte.class, Character.class, Double.class, Float.class, Integer.class, Long.class, Short.class)
+                .forEach(it -> context.register(new ClassReflectionModel(it.getName(), null, true, null, true /*valueOf*/, null, null, null, null, null, null)));
+    }
+
+    private void registerDictionaryResources(final Context context) {
+        context.register(new ResourceModel("org\\/apache\\/openjpa\\/jdbc\\/sql\\/sql-keywords\\.rsrc"));
+        context.register(new ResourceModel("org\\/apache\\/openjpa\\/jdbc\\/sql\\/sql-error-state-codes\\.xml"));
+    }
+
+    // todo: dbcp2-knight and inherit from it automatically?
+    private void registerDBCP2IfPresent(final Context context) {
+        try {
+            final Class<?> evictionPolicy = context.loadClass("org.apache.commons.pool2.impl.DefaultEvictionPolicy");
+
+            final ClassReflectionModel model = new ClassReflectionModel();
+            model.setName(evictionPolicy.getName());
+            model.setAllPublicConstructors(true);
+            context.register(model);
+
+            context.register(new ResourceBundleModel("org.apache.commons.dbcp2.LocalStrings"));
+
+            // dbcp2 depends on commons-logging in a hardcoded way (don't ask)
+            addCommonsLogging(context).forEach(it -> {
+                final ClassReflectionModel reflect = new ClassReflectionModel();
+                reflect.setName(it.getName());
+                reflect.setAllPublicConstructors(true);
+                reflect.setAllDeclaredConstructors(true);
+                context.register(reflect);
+            });
+        } catch (final NoClassDefFoundError | Exception e) {
+            // no-op
+        }
+    }
+
+    // todo: replace that by a ResourceFinder?
+    //       does not move often so maybe overkill but pattern being stable
+    //       (org/apache/openjpa/*/localizer.properties) we could
+    private void registerI18n(final Context context) {
+        final ClassLoader loader = Thread.currentThread().getContextClassLoader();
+        Stream.of(
+                "org/apache/openjpa/abstractstore/localizer.properties",
+                "org/apache/openjpa/ant/localizer.properties",
+                "org/apache/openjpa/conf/localizer.properties",
+                "org/apache/openjpa/datacache/localizer.properties",
+                "org/apache/openjpa/ee/localizer.properties",
+                "org/apache/openjpa/enhance/localizer.properties",
+                "org/apache/openjpa/enhance/stats/localizer.properties",
+                "org/apache/openjpa/event/kubernetes/localizer.properties",
+                "org/apache/openjpa/event/localizer.properties",
+                "org/apache/openjpa/instrumentation/jmx/localizer.properties",
+                "org/apache/openjpa/jdbc/ant/localizer.properties",
+                "org/apache/openjpa/jdbc/conf/localizer.properties",
+                "org/apache/openjpa/jdbc/kernel/exps/localizer.properties",
+                "org/apache/openjpa/jdbc/kernel/localizer.properties",
+                "org/apache/openjpa/jdbc/meta/localizer.properties",
+                "org/apache/openjpa/jdbc/meta/strats/localizer.properties",
+                "org/apache/openjpa/jdbc/schema/localizer.properties",
+                "org/apache/openjpa/jdbc/sql/localizer.properties",
+                "org/apache/openjpa/kernel/exps/localizer.properties",
+                "org/apache/openjpa/kernel/jpql/localizer.properties",
+                "org/apache/openjpa/kernel/localizer.properties",
+                "org/apache/openjpa/lib/ant/localizer.properties",
+                "org/apache/openjpa/lib/conf/localizer.properties",
+                "org/apache/openjpa/lib/graph/localizer.properties",
+                "org/apache/openjpa/lib/jdbc/localizer.properties",
+                "org/apache/openjpa/lib/log/localizer.properties",
+                "org/apache/openjpa/lib/meta/localizer.properties",
+                "org/apache/openjpa/lib/rop/localizer.properties",
+                "org/apache/openjpa/lib/util/localizer.properties",
+                "org/apache/openjpa/lib/xml/localizer.properties",
+                "org/apache/openjpa/meta/localizer.properties",
+                "org/apache/openjpa/persistence/criteria/localizer.properties",
+                "org/apache/openjpa/persistence/jdbc/localizer.properties",
+                "org/apache/openjpa/persistence/jest/localizer.properties",
+                "org/apache/openjpa/persistence/localizer.properties",
+                "org/apache/openjpa/persistence/meta/localizer.properties",
+                "org/apache/openjpa/persistence/util/localizer.properties",
+                "org/apache/openjpa/persistence/validation/localizer.properties",
+                "org/apache/openjpa/slice/jdbc/localizer.properties",
+                "org/apache/openjpa/slice/localizer.properties",
+                "org/apache/openjpa/slice/transaction/localizer.properties",
+                "org/apache/openjpa/util/localizer.properties"
+        ).filter(it -> loader.getResource(it) != null).forEach(it -> {
+            final ResourceBundleModel model = new ResourceBundleModel();
+            model.setName(it.replace('/', '.').substring(0, it.length() - ".properties".length()));
+            context.register(model);
+        });
+    }
+
+    private void registerSPI(final Context context) {
+        spiClasses(context)
+                .distinct()
+                .map(Class::getName)
+                .forEach(it -> {
+                    final ClassReflectionModel model = new ClassReflectionModel();
+                    model.setName(it);
+                    model.setAllPublicConstructors(true);
+                    model.setAllDeclaredConstructors(true);
+                    model.setAllPublicMethods(true);
+                    context.register(model);
+                });
+    }
+
+    // todo: cut more of that by a review of the reflection.arthur.json
+    // one option is to precompute it for a pure openjpa deployment and just add all user impl only
+    private Stream<? extends Class<?>> spiClasses(final Context context) {
+        return Stream.of(
+                "org.apache.openjpa.kernel.BrokerFactory",
+                "org.apache.openjpa.lib.log.LogFactory",
+                "org.apache.openjpa.lib.conf.Configurable",
+                "org.apache.openjpa.util.CacheMap",
+                "org.apache.openjpa.event.SingleJVMRemoteCommitProvider",
+                "org.apache.openjpa.event.SingleJVMRemoteCommitProvider",
+                "org.apache.openjpa.persistence.jdbc.PersistenceMappingFactory",
+                "org.apache.openjpa.jdbc.kernel.TableJDBCSeq",
+                "org.apache.openjpa.jdbc.kernel.ValueTableJDBCSeq",
+                "org.apache.openjpa.jdbc.kernel.ClassTableJDBCSeq",
+                "org.apache.openjpa.jdbc.kernel.NativeJDBCSeq",
+                "org.apache.openjpa.kernel.TimeSeededSeq",
+                "org.apache.openjpa.jdbc.kernel.TableJDBCSeq",
+                "org.apache.openjpa.jdbc.kernel.ClassTableJDBCSeq",
+                "org.apache.openjpa.kernel.TimeSeededSeq",
+                "org.apache.openjpa.persistence.EntityManagerFactoryImpl",
+                "org.apache.openjpa.jdbc.meta.MappingRepository",
+                "org.apache.openjpa.meta.MetaDataRepository",
+                "org.apache.openjpa.util.ClassResolverImpl",
+                "org.apache.openjpa.datacache.DataCacheManagerImpl",
+                "org.apache.openjpa.datacache.DefaultCacheDistributionPolicy",
+                "org.apache.openjpa.datacache.ConcurrentDataCache",
+                "org.apache.openjpa.datacache.ConcurrentQueryCache",
+                "org.apache.openjpa.kernel.NoneLockManager",
+                "org.apache.openjpa.kernel.VersionLockManager",
+                "org.apache.openjpa.kernel.InverseManager",
+                "org.apache.openjpa.kernel.InMemorySavepointManager",
+                "org.apache.openjpa.event.LogOrphanedKeyAction",
+                "org.apache.openjpa.event.ExceptionOrphanedKeyAction",
+                "org.apache.openjpa.event.NoneOrphanedKeyAction",
+                "org.apache.openjpa.ee.AutomaticManagedRuntime",
+                "org.apache.openjpa.ee.JNDIManagedRuntime",
+                "org.apache.openjpa.ee.InvocationManagedRuntime",
+                "org.apache.openjpa.util.ProxyManagerImpl",
+                "org.apache.openjpa.conf.DetachOptions$Loaded",
+                "org.apache.openjpa.conf.DetachOptions$FetchGroups",
+                "org.apache.openjpa.conf.DetachOptions$All",
+                "org.apache.openjpa.conf.Compatibility",
+                "org.apache.openjpa.conf.CallbackOptions",
+                "org.apache.openjpa.event.LifecycleEventManager",
+                "org.apache.openjpa.validation.ValidatingLifecycleEventManager",
+                "org.apache.openjpa.instrumentation.InstrumentationManagerImpl",
+                "org.apache.openjpa.audit.AuditLogger",
+                "org.apache.openjpa.jdbc.sql.DBDictionary",
+                "org.apache.openjpa.jdbc.kernel.AbstractUpdateManager",
+                "org.apache.openjpa.jdbc.schema.DriverDataSource",
+                "org.apache.openjpa.jdbc.schema.DynamicSchemaFactory",
+                "org.apache.openjpa.jdbc.schema.LazySchemaFactory",
+                "org.apache.openjpa.jdbc.schema.FileSchemaFactory",
+                "org.apache.openjpa.jdbc.schema.TableSchemaFactory",
+                "org.apache.openjpa.jdbc.sql.SQLFactoryImpl",
+                "org.apache.openjpa.jdbc.meta.MappingDefaultsImpl",
+                "org.apache.openjpa.jdbc.kernel.PreparedQueryCacheImpl",
+                "org.apache.openjpa.jdbc.kernel.FinderCacheImpl",
+                "org.apache.openjpa.jdbc.identifier.DBIdentifierUtilImpl",
+                "org.apache.openjpa.lib.log.LogFactoryImpl",
+                "org.apache.openjpa.lib.log.SLF4JLogFactory",
+                "org.apache.openjpa.lib.log.NoneLogFactory",
+                "org.apache.openjpa.slice.DistributionPolicy$Default",
+                "org.apache.openjpa.slice.ReplicationPolicy$Default",
+                "javax.persistence.spi.PersistenceProvider")
+                .distinct()
+                .map(it -> {
+                    try {
+                        return context.loadClass(it);
+                    } catch (final IllegalStateException | NoClassDefFoundError ise) {
+                        return null;
+                    }
+                })
+                .filter(Objects::nonNull)
+                .flatMap(context::findHierarchy)
+                .distinct()
+                .flatMap(it -> Stream.concat(Stream.of(it), context.findImplementations(it).stream()))
+                .distinct()
+                .filter(it -> needsReflection(it.getName()))
+                .flatMap(it -> {
+                    if (it.getName().startsWith("org.apache.commons.logging.impl.")) {
+                        try {
+                            context.loadClass("org.apache.commons.logging.impl.LogFactoryImpl").getConstructor().newInstance();
+                            return Stream.concat(Stream.of(it), addCommonsLogging(context));
+                        } catch (final NoClassDefFoundError | Exception e) {
+                            return Stream.empty();
+                        }
+                    }
+                    return Stream.of(it);
+                })
+                .filter(it -> {
+                    if ("org.apache.openjpa.jdbc.sql.PostgresDictionary".equals(it.getName())) {
+                        try {
+                            context.loadClass("org.postgresql.largeobject.LargeObjectManager");
+                            return true;
+                        } catch (final NoClassDefFoundError | Exception e) {
+                            return false;
+                        }
+                    }
+                    return true;
+                });
+    }
+
+    // todo: extract it in a commons-logging-knight and inherit from it automatically?
+    private Stream<? extends Class<?>> addCommonsLogging(final Context context) {
+        return Stream.of(
+                "org.apache.commons.logging.LogFactory",
+                "org.apache.commons.logging.impl.LogFactoryImpl",
+                "org.apache.commons.logging.impl.Jdk14Logger")
+                .map(n -> {
+                    try {
+                        return context.loadClass(n);
+                    } catch (final NoClassDefFoundError | Exception ex) {
+                        return null;
+                    }
+                })
+                .filter(Objects::nonNull);
+    }
+
+    private boolean needsReflection(final String name) {
+        return !name.equals("org.apache.openjpa.ee.OSGiManagedRuntime") &&
+                !name.startsWith("org.apache.openjpa.ee.WAS") &&
+                !name.startsWith("org.slf4j.") &&
+                !name.startsWith("org.apache.commons.") &&
+                !name.startsWith("java.") &&
+                !name.startsWith("javax.") &&
+                !name.startsWith("jakarta.") &&
+                !name.contains("$util") &&
+                !name.contains("$1") &&
+                !name.startsWith("org.apache.openjpa.lib.jdbc.LoggingConnectionDecorator$") &&
+                !(name.endsWith("Comparator") && name.contains("$"));
+    }
+
+    private void registerJPAClasses(final Context context) {
+        Stream.of(Entity.class, MappedSuperclass.class, Embeddable.class)
+                .flatMap(it -> context.findAnnotatedClasses(it).stream())
+                .flatMap(context::findHierarchy)
+                .distinct()
+                .flatMap(it -> {
+                    final ClassReflectionModel entity = new ClassReflectionModel();
+                    entity.setName(it.getName());
+                    entity.setAllPublicConstructors(true);
+                    entity.setAllPublicMethods(true);
+                    entity.setAllDeclaredConstructors(true);
+                    entity.setAllDeclaredFields(true);
+                    entity.setAllDeclaredMethods(true);
+                    return Stream.concat(Stream.of(entity), extractFieldTypesForReflection(it));
+                })
+                .distinct()
+                .forEach(context::register);
+    }
+
+    private Stream<ClassReflectionModel> extractFieldTypesForReflection(final Class<?> entity) {
+        try {
+            final Field pcFieldTypes = entity.getDeclaredField("pcFieldTypes");
+            pcFieldTypes.setAccessible(true);
+            final Object types = pcFieldTypes.get(null);
+            return Stream.of(Class[].class.cast(types))
+                    .distinct() // todo: filter(it -> !it.isPrimitive())?
+                    .map(type -> {
+                        final ClassReflectionModel fieldType = new ClassReflectionModel();
+                        fieldType.setName(type.getName());
+                        return fieldType;
+                    });
+        } catch (final Exception e) {
+            return Stream.empty();
+        }
+    }
+}
diff --git a/knights/openjpa-knight/src/main/resources/META-INF/services/org.apache.geronimo.arthur.spi.ArthurExtension b/knights/openjpa-knight/src/main/resources/META-INF/services/org.apache.geronimo.arthur.spi.ArthurExtension
new file mode 100644
index 0000000..9886174
--- /dev/null
+++ b/knights/openjpa-knight/src/main/resources/META-INF/services/org.apache.geronimo.arthur.spi.ArthurExtension
@@ -0,0 +1 @@
+org.apache.geronimo.arthur.knight.openjpa.OpenJPAExtension
diff --git a/knights/pom.xml b/knights/pom.xml
index 9d27f40..ab0d1b6 100644
--- a/knights/pom.xml
+++ b/knights/pom.xml
@@ -33,6 +33,8 @@
     <module>winegrower-knight</module>
     <module>openwebbeans-knight</module>
     <module>slf4j-knight</module>
+    <module>openjpa-knight</module>
+    <module>derby-knight</module>
   </modules>
 
   <dependencies>