diff --git a/fabric-data-generation-api-v1/src/main/java/net/fabricmc/fabric/api/datagen/v1/provider/FabricCodecDataProvider.java b/fabric-data-generation-api-v1/src/main/java/net/fabricmc/fabric/api/datagen/v1/provider/FabricCodecDataProvider.java
index 86190079b..36d8b5a97 100644
--- a/fabric-data-generation-api-v1/src/main/java/net/fabricmc/fabric/api/datagen/v1/provider/FabricCodecDataProvider.java
+++ b/fabric-data-generation-api-v1/src/main/java/net/fabricmc/fabric/api/datagen/v1/provider/FabricCodecDataProvider.java
@@ -19,38 +19,74 @@ package net.fabricmc.fabric.api.datagen.v1.provider;
 import java.nio.file.Path;
 import java.util.HashMap;
 import java.util.Map;
+import java.util.Objects;
 import java.util.concurrent.CompletableFuture;
 import java.util.function.BiConsumer;
 
 import com.google.gson.JsonElement;
 import com.mojang.serialization.Codec;
 import com.mojang.serialization.DataResult;
+import com.mojang.serialization.DynamicOps;
 import com.mojang.serialization.JsonOps;
 
 import net.minecraft.data.DataOutput;
 import net.minecraft.data.DataProvider;
 import net.minecraft.data.DataWriter;
+import net.minecraft.registry.RegistryOps;
+import net.minecraft.registry.RegistryWrapper;
 import net.minecraft.util.Identifier;
 
 import net.fabricmc.fabric.api.datagen.v1.FabricDataGenerator;
 import net.fabricmc.fabric.api.datagen.v1.FabricDataOutput;
 
 /**
- * Extend this class and implement {@link FabricCodecDataProvider#configure}.
+ * Extend this class and implement {@link FabricCodecDataProvider#configure(BiConsumer, RegistryWrapper.WrapperLookup)}.
  *
  * <p>Register an instance of the class with {@link FabricDataGenerator.Pack#addProvider} in a {@link net.fabricmc.fabric.api.datagen.v1.DataGeneratorEntrypoint}.
  */
 public abstract class FabricCodecDataProvider<T> implements DataProvider {
 	private final DataOutput.PathResolver pathResolver;
+	private final CompletableFuture<RegistryWrapper.WrapperLookup> registriesFuture;
 	private final Codec<T> codec;
 
+	/**
+	 * @deprecated Please use {@link FabricCodecDataProvider#FabricCodecDataProvider(FabricDataOutput, CompletableFuture, DataOutput.OutputType, String, Codec)}.
+	 */
+	@Deprecated()
 	protected FabricCodecDataProvider(FabricDataOutput dataOutput, DataOutput.OutputType outputType, String directoryName, Codec<T> codec) {
 		this.pathResolver = dataOutput.getResolver(outputType, directoryName);
+		this.registriesFuture = null;
+		this.codec = codec;
+	}
+
+	protected FabricCodecDataProvider(FabricDataOutput dataOutput, CompletableFuture<RegistryWrapper.WrapperLookup> registriesFuture, DataOutput.OutputType outputType, String directoryName, Codec<T> codec) {
+		this.pathResolver = dataOutput.getResolver(outputType, directoryName);
+		this.registriesFuture = Objects.requireNonNull(registriesFuture);
 		this.codec = codec;
 	}
 
 	@Override
 	public CompletableFuture<?> run(DataWriter writer) {
+		// TODO: Remove the null check once the deprecated method and constructor are removed.
+		if (this.registriesFuture != null) {
+			return this.registriesFuture.thenCompose(lookup -> {
+				Map<Identifier, JsonElement> entries = new HashMap<>();
+				RegistryOps<JsonElement> ops = RegistryOps.of(JsonOps.INSTANCE, lookup);
+
+				BiConsumer<Identifier, T> provider = (id, value) -> {
+					JsonElement json = this.convert(id, value, ops);
+					JsonElement existingJson = entries.put(id, json);
+
+					if (existingJson != null) {
+						throw new IllegalArgumentException("Duplicate entry " + id);
+					}
+				};
+
+				this.configure(provider, lookup);
+				return this.write(writer, entries);
+			});
+		}
+
 		Map<Identifier, JsonElement> entries = new HashMap<>();
 		BiConsumer<Identifier, T> provider = (id, value) -> {
 			JsonElement json = this.convert(id, value);
@@ -69,11 +105,29 @@ public abstract class FabricCodecDataProvider<T> implements DataProvider {
 	 * Implement this method to register entries to generate.
 	 *
 	 * @param provider A consumer that accepts an {@link Identifier} and a value to register.
+	 * @deprecated Please use {@link FabricCodecDataProvider#configure(BiConsumer, RegistryWrapper.WrapperLookup)}.
 	 */
-	protected abstract void configure(BiConsumer<Identifier, T> provider);
+	@Deprecated()
+	protected void configure(BiConsumer<Identifier, T> provider) {
+		throw new UnsupportedOperationException("Override this method.");
+	}
+
+	/**
+	 * Implement this method to register entries to generate using a {@link RegistryWrapper.WrapperLookup}.
+	 * @param provider A consumer that accepts an {@link Identifier} and a value to register.
+	 * @param lookup A lookup for registries.
+	 */
+	protected void configure(BiConsumer<Identifier, T> provider, RegistryWrapper.WrapperLookup lookup) {
+		// TODO: Make abstract once the deprecated method is removed.
+		throw new UnsupportedOperationException("Override this method.");
+	}
 
 	private JsonElement convert(Identifier id, T value) {
-		DataResult<JsonElement> dataResult = this.codec.encodeStart(JsonOps.INSTANCE, value);
+		return this.convert(id, value, JsonOps.INSTANCE);
+	}
+
+	private JsonElement convert(Identifier id, T value, DynamicOps<JsonElement> ops) {
+		DataResult<JsonElement> dataResult = this.codec.encodeStart(ops, value);
 		return dataResult.get()
 				.mapRight(partial -> "Invalid entry %s: %s".formatted(id, partial.message()))
 				.orThrow();
diff --git a/fabric-data-generation-api-v1/src/testmod/java/net/fabricmc/fabric/test/datagen/DataGeneratorTestEntrypoint.java b/fabric-data-generation-api-v1/src/testmod/java/net/fabricmc/fabric/test/datagen/DataGeneratorTestEntrypoint.java
index 559cb3068..d42da1518 100644
--- a/fabric-data-generation-api-v1/src/testmod/java/net/fabricmc/fabric/test/datagen/DataGeneratorTestEntrypoint.java
+++ b/fabric-data-generation-api-v1/src/testmod/java/net/fabricmc/fabric/test/datagen/DataGeneratorTestEntrypoint.java
@@ -34,6 +34,8 @@ import java.util.concurrent.CompletableFuture;
 import java.util.function.BiConsumer;
 import java.util.function.Consumer;
 
+import com.mojang.serialization.Codec;
+import com.mojang.serialization.codecs.RecordCodecBuilder;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -41,7 +43,10 @@ import net.minecraft.advancement.Advancement;
 import net.minecraft.advancement.AdvancementEntry;
 import net.minecraft.advancement.AdvancementFrame;
 import net.minecraft.advancement.criterion.OnKilledCriterion;
+import net.minecraft.block.Block;
+import net.minecraft.block.BlockKeys;
 import net.minecraft.block.Blocks;
+import net.minecraft.data.DataOutput;
 import net.minecraft.data.client.BlockStateModelGenerator;
 import net.minecraft.data.client.ItemModelGenerator;
 import net.minecraft.data.server.recipe.RecipeExporter;
@@ -53,6 +58,9 @@ import net.minecraft.item.Items;
 import net.minecraft.loot.LootPool;
 import net.minecraft.loot.LootTable;
 import net.minecraft.loot.LootTables;
+import net.minecraft.loot.condition.BlockStatePropertyLootCondition;
+import net.minecraft.loot.condition.LootCondition;
+import net.minecraft.loot.condition.LootConditionTypes;
 import net.minecraft.loot.context.LootContextTypes;
 import net.minecraft.loot.entry.ItemEntry;
 import net.minecraft.loot.provider.number.ConstantLootNumberProvider;
@@ -60,8 +68,11 @@ import net.minecraft.recipe.Ingredient;
 import net.minecraft.recipe.book.RecipeCategory;
 import net.minecraft.registry.Registerable;
 import net.minecraft.registry.RegistryBuilder;
+import net.minecraft.registry.RegistryEntryLookup;
 import net.minecraft.registry.RegistryKeys;
 import net.minecraft.registry.RegistryWrapper;
+import net.minecraft.registry.entry.RegistryEntry;
+import net.minecraft.registry.entry.RegistryFixedCodec;
 import net.minecraft.registry.tag.BlockTags;
 import net.minecraft.registry.tag.ItemTags;
 import net.minecraft.registry.tag.TagKey;
@@ -77,6 +88,7 @@ import net.fabricmc.fabric.api.datagen.v1.FabricDataOutput;
 import net.fabricmc.fabric.api.datagen.v1.JsonKeySortOrderCallback;
 import net.fabricmc.fabric.api.datagen.v1.provider.FabricAdvancementProvider;
 import net.fabricmc.fabric.api.datagen.v1.provider.FabricBlockLootTableProvider;
+import net.fabricmc.fabric.api.datagen.v1.provider.FabricCodecDataProvider;
 import net.fabricmc.fabric.api.datagen.v1.provider.FabricDynamicRegistryProvider;
 import net.fabricmc.fabric.api.datagen.v1.provider.FabricLanguageProvider;
 import net.fabricmc.fabric.api.datagen.v1.provider.FabricModelProvider;
@@ -110,6 +122,8 @@ public class DataGeneratorTestEntrypoint implements DataGeneratorEntrypoint {
 		pack.addProvider(ExistingEnglishLangProvider::new);
 		pack.addProvider(JapaneseLangProvider::new);
 		pack.addProvider(TestDynamicRegistryProvider::new);
+		pack.addProvider(TestPredicateProvider::new);
+		pack.addProvider(TestCustomCodecProvider::new);
 
 		TestBlockTagProvider blockTagProvider = pack.addProvider(TestBlockTagProvider::new);
 		pack.addProvider((output, registries) -> new TestItemTagProvider(output, registries, blockTagProvider));
@@ -410,4 +424,45 @@ public class DataGeneratorTestEntrypoint implements DataGeneratorEntrypoint {
 			return "Test Dynamic Registry";
 		}
 	}
+
+	private static class TestPredicateProvider extends FabricCodecDataProvider<LootCondition> {
+		private TestPredicateProvider(FabricDataOutput dataOutput, CompletableFuture<RegistryWrapper.WrapperLookup> registriesFuture) {
+			super(dataOutput, registriesFuture, DataOutput.OutputType.DATA_PACK, "predicates", LootConditionTypes.CODEC);
+		}
+
+		@Override
+		protected void configure(BiConsumer<Identifier, LootCondition> provider, RegistryWrapper.WrapperLookup lookup) {
+			RegistryEntryLookup<Block> blocks = lookup.createRegistryLookup().getOrThrow(RegistryKeys.BLOCK);
+			provider.accept(new Identifier(MOD_ID, "predicate_test"), BlockStatePropertyLootCondition.builder(
+					blocks.getOrThrow(BlockKeys.MELON).value()).build()); // Pretend this actually does something and we cannot access the blocks directly
+		}
+
+		@Override
+		public String getName() {
+			return "Predicates";
+		}
+	}
+
+	private static class TestCustomCodecProvider extends FabricCodecDataProvider<TestCustomCodecProvider.Entry> {
+		private TestCustomCodecProvider(FabricDataOutput dataOutput, CompletableFuture<RegistryWrapper.WrapperLookup> registriesFuture) {
+			super(dataOutput, registriesFuture, DataOutput.OutputType.DATA_PACK, "biome_entry", Entry.CODEC);
+		}
+
+		@Override
+		protected void configure(BiConsumer<Identifier, Entry> provider, RegistryWrapper.WrapperLookup lookup) {
+			RegistryEntryLookup<Biome> biomes = lookup.createRegistryLookup().getOrThrow(RegistryKeys.BIOME);
+			provider.accept(new Identifier(MOD_ID, "custom_codec_test"), new Entry(biomes.getOrThrow(BiomeKeys.PLAINS)));
+		}
+
+		@Override
+		public String getName() {
+			return "Codec Test Using Dynamic Registry";
+		}
+
+		private record Entry(RegistryEntry<Biome> biome) {
+			private static final Codec<Entry> CODEC = RecordCodecBuilder.create(instance -> instance.group(
+					RegistryFixedCodec.of(RegistryKeys.BIOME).fieldOf("biome").forGetter(Entry::biome)
+			).apply(instance, Entry::new));
+		}
+	}
 }