diff --git a/fabric-lifecycle-events-v1/src/main/java/net/fabricmc/fabric/api/client/event/lifecycle/v1/ClientBlockEntityEvents.java b/fabric-lifecycle-events-v1/src/main/java/net/fabricmc/fabric/api/client/event/lifecycle/v1/ClientBlockEntityEvents.java
index ec901429b..eff510dd8 100644
--- a/fabric-lifecycle-events-v1/src/main/java/net/fabricmc/fabric/api/client/event/lifecycle/v1/ClientBlockEntityEvents.java
+++ b/fabric-lifecycle-events-v1/src/main/java/net/fabricmc/fabric/api/client/event/lifecycle/v1/ClientBlockEntityEvents.java
@@ -78,10 +78,12 @@ public final class ClientBlockEntityEvents {
 		}
 	});
 
+	@FunctionalInterface
 	public interface Load {
 		void onLoad(BlockEntity blockEntity, ClientWorld world);
 	}
 
+	@FunctionalInterface
 	public interface Unload {
 		void onUnload(BlockEntity blockEntity, ClientWorld world);
 	}
diff --git a/fabric-lifecycle-events-v1/src/main/java/net/fabricmc/fabric/api/client/event/lifecycle/v1/ClientChunkEvents.java b/fabric-lifecycle-events-v1/src/main/java/net/fabricmc/fabric/api/client/event/lifecycle/v1/ClientChunkEvents.java
index 7ce0387ad..ad5350c68 100644
--- a/fabric-lifecycle-events-v1/src/main/java/net/fabricmc/fabric/api/client/event/lifecycle/v1/ClientChunkEvents.java
+++ b/fabric-lifecycle-events-v1/src/main/java/net/fabricmc/fabric/api/client/event/lifecycle/v1/ClientChunkEvents.java
@@ -78,10 +78,12 @@ public final class ClientChunkEvents {
 		}
 	});
 
+	@FunctionalInterface
 	public interface Load {
 		void onChunkLoad(ClientWorld world, WorldChunk chunk);
 	}
 
+	@FunctionalInterface
 	public interface Unload {
 		void onChunkUnload(ClientWorld world, WorldChunk chunk);
 	}
diff --git a/fabric-lifecycle-events-v1/src/main/java/net/fabricmc/fabric/api/client/event/lifecycle/v1/ClientEntityEvents.java b/fabric-lifecycle-events-v1/src/main/java/net/fabricmc/fabric/api/client/event/lifecycle/v1/ClientEntityEvents.java
index c8ced1a4b..f4ee6d837 100644
--- a/fabric-lifecycle-events-v1/src/main/java/net/fabricmc/fabric/api/client/event/lifecycle/v1/ClientEntityEvents.java
+++ b/fabric-lifecycle-events-v1/src/main/java/net/fabricmc/fabric/api/client/event/lifecycle/v1/ClientEntityEvents.java
@@ -78,10 +78,12 @@ public final class ClientEntityEvents {
 		}
 	});
 
+	@FunctionalInterface
 	public interface Load {
 		void onLoad(Entity entity, ClientWorld world);
 	}
 
+	@FunctionalInterface
 	public interface Unload {
 		void onUnload(Entity entity, ClientWorld world);
 	}
diff --git a/fabric-lifecycle-events-v1/src/main/java/net/fabricmc/fabric/api/client/event/lifecycle/v1/ClientLifecycleEvents.java b/fabric-lifecycle-events-v1/src/main/java/net/fabricmc/fabric/api/client/event/lifecycle/v1/ClientLifecycleEvents.java
index 88ce5cac4..045e29824 100644
--- a/fabric-lifecycle-events-v1/src/main/java/net/fabricmc/fabric/api/client/event/lifecycle/v1/ClientLifecycleEvents.java
+++ b/fabric-lifecycle-events-v1/src/main/java/net/fabricmc/fabric/api/client/event/lifecycle/v1/ClientLifecycleEvents.java
@@ -51,10 +51,12 @@ public final class ClientLifecycleEvents {
 		}
 	});
 
+	@FunctionalInterface
 	public interface ClientStarted {
 		void onClientStarted(MinecraftClient client);
 	}
 
+	@FunctionalInterface
 	public interface ClientStopping {
 		void onClientStopping(MinecraftClient client);
 	}
diff --git a/fabric-lifecycle-events-v1/src/main/java/net/fabricmc/fabric/api/client/event/lifecycle/v1/ClientTickEvents.java b/fabric-lifecycle-events-v1/src/main/java/net/fabricmc/fabric/api/client/event/lifecycle/v1/ClientTickEvents.java
index 07b3eb9c1..5eb0d52b0 100644
--- a/fabric-lifecycle-events-v1/src/main/java/net/fabricmc/fabric/api/client/event/lifecycle/v1/ClientTickEvents.java
+++ b/fabric-lifecycle-events-v1/src/main/java/net/fabricmc/fabric/api/client/event/lifecycle/v1/ClientTickEvents.java
@@ -120,18 +120,22 @@ public final class ClientTickEvents {
 		}
 	});
 
+	@FunctionalInterface
 	public interface StartTick {
 		void onStartTick(MinecraftClient client);
 	}
 
+	@FunctionalInterface
 	public interface EndTick {
 		void onEndTick(MinecraftClient client);
 	}
 
+	@FunctionalInterface
 	public interface StartWorldTick {
 		void onStartTick(ClientWorld world);
 	}
 
+	@FunctionalInterface
 	public interface EndWorldTick {
 		void onEndTick(ClientWorld world);
 	}
diff --git a/fabric-lifecycle-events-v1/src/main/java/net/fabricmc/fabric/api/event/lifecycle/v1/ServerBlockEntityEvents.java b/fabric-lifecycle-events-v1/src/main/java/net/fabricmc/fabric/api/event/lifecycle/v1/ServerBlockEntityEvents.java
index 5418bfb1b..0527aa071 100644
--- a/fabric-lifecycle-events-v1/src/main/java/net/fabricmc/fabric/api/event/lifecycle/v1/ServerBlockEntityEvents.java
+++ b/fabric-lifecycle-events-v1/src/main/java/net/fabricmc/fabric/api/event/lifecycle/v1/ServerBlockEntityEvents.java
@@ -75,10 +75,12 @@ public final class ServerBlockEntityEvents {
 		}
 	});
 
+	@FunctionalInterface
 	public interface Load {
 		void onLoad(BlockEntity blockEntity, ServerWorld world);
 	}
 
+	@FunctionalInterface
 	public interface Unload {
 		void onUnload(BlockEntity blockEntity, ServerWorld world);
 	}
diff --git a/fabric-lifecycle-events-v1/src/main/java/net/fabricmc/fabric/api/event/lifecycle/v1/ServerChunkEvents.java b/fabric-lifecycle-events-v1/src/main/java/net/fabricmc/fabric/api/event/lifecycle/v1/ServerChunkEvents.java
index af495363e..0d2515e46 100644
--- a/fabric-lifecycle-events-v1/src/main/java/net/fabricmc/fabric/api/event/lifecycle/v1/ServerChunkEvents.java
+++ b/fabric-lifecycle-events-v1/src/main/java/net/fabricmc/fabric/api/event/lifecycle/v1/ServerChunkEvents.java
@@ -75,10 +75,12 @@ public final class ServerChunkEvents {
 		}
 	});
 
+	@FunctionalInterface
 	public interface Load {
 		void onChunkLoad(ServerWorld world, WorldChunk chunk);
 	}
 
+	@FunctionalInterface
 	public interface Unload {
 		void onChunkUnload(ServerWorld world, WorldChunk chunk);
 	}
diff --git a/fabric-lifecycle-events-v1/src/main/java/net/fabricmc/fabric/api/event/lifecycle/v1/ServerEntityEvents.java b/fabric-lifecycle-events-v1/src/main/java/net/fabricmc/fabric/api/event/lifecycle/v1/ServerEntityEvents.java
index 9166bf0f4..ab0333cb4 100644
--- a/fabric-lifecycle-events-v1/src/main/java/net/fabricmc/fabric/api/event/lifecycle/v1/ServerEntityEvents.java
+++ b/fabric-lifecycle-events-v1/src/main/java/net/fabricmc/fabric/api/event/lifecycle/v1/ServerEntityEvents.java
@@ -53,6 +53,7 @@ public final class ServerEntityEvents {
 		}
 	});
 
+	@FunctionalInterface
 	public interface Load {
 		void onLoad(Entity entity, ServerWorld world);
 	}
diff --git a/fabric-lifecycle-events-v1/src/main/java/net/fabricmc/fabric/api/event/lifecycle/v1/ServerLifecycleEvents.java b/fabric-lifecycle-events-v1/src/main/java/net/fabricmc/fabric/api/event/lifecycle/v1/ServerLifecycleEvents.java
index 50bf8a507..e6f04acc4 100644
--- a/fabric-lifecycle-events-v1/src/main/java/net/fabricmc/fabric/api/event/lifecycle/v1/ServerLifecycleEvents.java
+++ b/fabric-lifecycle-events-v1/src/main/java/net/fabricmc/fabric/api/event/lifecycle/v1/ServerLifecycleEvents.java
@@ -96,26 +96,32 @@ public final class ServerLifecycleEvents {
 		}
 	});
 
+	@FunctionalInterface
 	public interface ServerStarting {
 		void onServerStarting(MinecraftServer server);
 	}
 
+	@FunctionalInterface
 	public interface ServerStarted {
 		void onServerStarted(MinecraftServer server);
 	}
 
+	@FunctionalInterface
 	public interface ServerStopping {
 		void onServerStopping(MinecraftServer server);
 	}
 
+	@FunctionalInterface
 	public interface ServerStopped {
 		void onServerStopped(MinecraftServer server);
 	}
 
+	@FunctionalInterface
 	public interface StartDataPackReload {
 		void startDataPackReload(MinecraftServer server, ServerResourceManager serverResourceManager);
 	}
 
+	@FunctionalInterface
 	public interface EndDataPackReload {
 		/**
 		 * Called after data packs on a Minecraft server have been reloaded.
diff --git a/fabric-lifecycle-events-v1/src/main/java/net/fabricmc/fabric/api/event/lifecycle/v1/ServerTickEvents.java b/fabric-lifecycle-events-v1/src/main/java/net/fabricmc/fabric/api/event/lifecycle/v1/ServerTickEvents.java
index 9b9d2662f..c4200cc1b 100644
--- a/fabric-lifecycle-events-v1/src/main/java/net/fabricmc/fabric/api/event/lifecycle/v1/ServerTickEvents.java
+++ b/fabric-lifecycle-events-v1/src/main/java/net/fabricmc/fabric/api/event/lifecycle/v1/ServerTickEvents.java
@@ -117,18 +117,22 @@ public final class ServerTickEvents {
 		}
 	});
 
+	@FunctionalInterface
 	public interface StartTick {
 		void onStartTick(MinecraftServer server);
 	}
 
+	@FunctionalInterface
 	public interface EndTick {
 		void onEndTick(MinecraftServer server);
 	}
 
+	@FunctionalInterface
 	public interface StartWorldTick {
 		void onStartTick(ServerWorld world);
 	}
 
+	@FunctionalInterface
 	public interface EndWorldTick {
 		void onEndTick(ServerWorld world);
 	}
diff --git a/fabric-lifecycle-events-v1/src/main/java/net/fabricmc/fabric/api/event/lifecycle/v1/ServerWorldEvents.java b/fabric-lifecycle-events-v1/src/main/java/net/fabricmc/fabric/api/event/lifecycle/v1/ServerWorldEvents.java
index ca47bed62..29da25965 100644
--- a/fabric-lifecycle-events-v1/src/main/java/net/fabricmc/fabric/api/event/lifecycle/v1/ServerWorldEvents.java
+++ b/fabric-lifecycle-events-v1/src/main/java/net/fabricmc/fabric/api/event/lifecycle/v1/ServerWorldEvents.java
@@ -35,10 +35,28 @@ public final class ServerWorldEvents {
 		}
 	});
 
+	/**
+	 * Called before a world is unloaded by a Minecraft server.
+	 *
+	 * <p>This typically occurs after a server has {@link ServerLifecycleEvents#SERVER_STOPPING started shutting down}.
+	 * Mods which allow dynamic world (un)registration should use this event so mods can let go of world handles when a world is removed.
+	 */
+	public static final Event<Unload> UNLOAD = EventFactory.createArrayBacked(Unload.class, callbacks -> (server, world) -> {
+		for (Unload callback : callbacks) {
+			callback.onWorldUnload(server, world);
+		}
+	});
+
+	@FunctionalInterface
 	public interface Load {
 		void onWorldLoad(MinecraftServer server, ServerWorld world);
 	}
 
+	@FunctionalInterface
+	public interface Unload {
+		void onWorldUnload(MinecraftServer server, ServerWorld world);
+	}
+
 	private ServerWorldEvents() {
 	}
 }
diff --git a/fabric-lifecycle-events-v1/src/main/java/net/fabricmc/fabric/mixin/event/lifecycle/MinecraftServerMixin.java b/fabric-lifecycle-events-v1/src/main/java/net/fabricmc/fabric/mixin/event/lifecycle/MinecraftServerMixin.java
index ff62491f4..d5f6e46d8 100644
--- a/fabric-lifecycle-events-v1/src/main/java/net/fabricmc/fabric/mixin/event/lifecycle/MinecraftServerMixin.java
+++ b/fabric-lifecycle-events-v1/src/main/java/net/fabricmc/fabric/mixin/event/lifecycle/MinecraftServerMixin.java
@@ -96,6 +96,11 @@ public abstract class MinecraftServerMixin {
 		return result;
 	}
 
+	@Inject(method = "shutdown", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/world/ServerWorld;close()V", shift = At.Shift.AFTER), locals = LocalCapture.CAPTURE_FAILEXCEPTION)
+	private void onUnloadWorldAtShutdown(CallbackInfo ci, Iterator<ServerWorld> worlds, ServerWorld world) {
+		ServerWorldEvents.UNLOAD.invoker().onWorldUnload((MinecraftServer) (Object) this, world);
+	}
+
 	@Inject(method = "reloadResources", at = @At("HEAD"))
 	private void startResourceReload(Collection<String> collection, CallbackInfoReturnable<CompletableFuture<Void>> cir) {
 		ServerLifecycleEvents.START_DATA_PACK_RELOAD.invoker().startDataPackReload((MinecraftServer) (Object) this, this.serverResourceManager);
diff --git a/fabric-lifecycle-events-v1/src/testmod/java/net/fabricmc/fabric/test/event/lifecycle/ServerLifecycleTests.java b/fabric-lifecycle-events-v1/src/testmod/java/net/fabricmc/fabric/test/event/lifecycle/ServerLifecycleTests.java
index 59f5dfb3a..d773930e7 100644
--- a/fabric-lifecycle-events-v1/src/testmod/java/net/fabricmc/fabric/test/event/lifecycle/ServerLifecycleTests.java
+++ b/fabric-lifecycle-events-v1/src/testmod/java/net/fabricmc/fabric/test/event/lifecycle/ServerLifecycleTests.java
@@ -46,5 +46,9 @@ public class ServerLifecycleTests implements ModInitializer {
 		ServerWorldEvents.LOAD.register((server, world) -> {
 			LOGGER.info("Loaded world " + world.getRegistryKey().getValue().toString());
 		});
+
+		ServerWorldEvents.UNLOAD.register((server, world) -> {
+			LOGGER.info("Unloaded world " + world.getRegistryKey().getValue().toString());
+		});
 	}
 }