--- a/net/minecraft/core/registries/BuiltInRegistries.java
+++ b/net/minecraft/core/registries/BuiltInRegistries.java
@@ -336,6 +_,11 @@
     public static final Registry<MapCodec<? extends DialogBody>> DIALOG_BODY_TYPE = registerSimple(Registries.DIALOG_BODY_TYPE, DialogBodyTypes::bootstrap);
     public static final Registry<Consumer<GameTestHelper>> TEST_FUNCTION = registerSimple(Registries.TEST_FUNCTION, BuiltinTestFunctions::bootstrap);
     public static final Registry<? extends Registry<?>> REGISTRY = WRITABLE_REGISTRY;
+    // Paper start - add built-in registry conversions
+    public static final io.papermc.paper.registry.data.util.Conversions STATIC_ACCESS_CONVERSIONS = new io.papermc.paper.registry.data.util.Conversions(
+        new net.minecraft.resources.RegistryOps.HolderLookupAdapter(net.minecraft.server.RegistryLayer.STATIC_ACCESS)
+    );
+    // Paper end - add built-in registry conversions
 
     private static <T> Registry<T> registerSimple(ResourceKey<? extends Registry<T>> key, BuiltInRegistries.RegistryBootstrap<T> bootstrap) {
         return internalRegister(key, new MappedRegistry<>(key, Lifecycle.stable(), false), bootstrap);
@@ -361,6 +_,7 @@
         ResourceKey<? extends Registry<T>> key, R registry, BuiltInRegistries.RegistryBootstrap<T> bootstrap
     ) {
         Bootstrap.checkBootstrapCalled(() -> "registry " + key.location());
+        io.papermc.paper.registry.PaperRegistryAccess.instance().registerRegistry(registry); // Paper - initialize API registry
         ResourceLocation resourceLocation = key.location();
         LOADERS.put(resourceLocation, () -> bootstrap.run(registry));
         WRITABLE_REGISTRY.register((ResourceKey)key, registry, RegistrationInfo.BUILT_IN);
@@ -368,16 +_,34 @@
     }
 
     public static void bootStrap() {
+        // Paper start
+        bootStrap(() -> {});
+    }
+    public static void bootStrap(Runnable runnable) {
+        // Paper end
+        REGISTRY.freeze(); // Paper - freeze main registry early
         createContents();
+        runnable.run(); // Paper
         freeze();
         validate(REGISTRY);
     }
 
     private static void createContents() {
+        // Paper start - class-load org.bukkit.Registry
+        // we have to class-load Registry here to create all the CraftRegistry instances
+        // that will be created when Registry is class-loaded before RegistryAccess#getRegistry
+        // would try to create them in lockReferenceHolder
+        try {
+            Class.forName(org.bukkit.Registry.class.getName());
+        } catch (final ClassNotFoundException ex) {
+            throw new RuntimeException(ex);
+        }
+        // Paper end - class-load org.bukkit.Registry
         LOADERS.forEach((resourceLocation, supplier) -> {
             if (supplier.get() == null) {
                 LOGGER.error("Unable to bootstrap registry '{}'", resourceLocation);
             }
+            io.papermc.paper.registry.PaperRegistryAccess.instance().lockReferenceHolders(ResourceKey.createRegistryKey(resourceLocation)); // Paper - lock reference holder creation
         });
     }
 
@@ -386,6 +_,7 @@
 
         for (Registry<?> registry : REGISTRY) {
             bindBootstrappedTagsToEmpty(registry);
+            io.papermc.paper.registry.PaperRegistryListenerManager.INSTANCE.runFreezeListeners(registry.key(), STATIC_ACCESS_CONVERSIONS); // Paper
             registry.freeze();
         }
     }
