diff --git a/paper-api/src/main/java/org/bukkit/inventory/MenuType.java b/paper-api/src/main/java/org/bukkit/inventory/MenuType.java
index 2442361ce7..eb64a5ef29 100644
--- a/paper-api/src/main/java/org/bukkit/inventory/MenuType.java
+++ b/paper-api/src/main/java/org/bukkit/inventory/MenuType.java
@@ -1,5 +1,6 @@
 package org.bukkit.inventory;
 
+import net.kyori.adventure.text.Component;
 import org.bukkit.Keyed;
 import org.bukkit.NamespacedKey;
 import org.bukkit.Registry;
@@ -18,12 +19,14 @@ import org.bukkit.inventory.view.builder.InventoryViewBuilder;
 import org.bukkit.inventory.view.builder.LocationInventoryViewBuilder;
 import org.bukkit.inventory.view.builder.MerchantInventoryViewBuilder;
 import org.jetbrains.annotations.ApiStatus;
-import org.jetbrains.annotations.NotNull;
+import org.jspecify.annotations.NullMarked;
+import org.jspecify.annotations.Nullable;
 
 /**
  * Represents different kinds of views, also known as menus, which can be
  * created and viewed by the player.
  */
+@NullMarked
 @ApiStatus.Experimental
 public interface MenuType extends Keyed, io.papermc.paper.world.flag.FeatureDependant { // Paper - make FeatureDependant
 
@@ -138,6 +141,20 @@ public interface MenuType extends Keyed, io.papermc.paper.world.flag.FeatureDepe
      */
     interface Typed<V extends InventoryView, B extends InventoryViewBuilder<V>> extends MenuType {
 
+        /**
+         * Creates a view of the specified menu type.
+         * <p>
+         * The player provided to create this view must be the player the view
+         * is opened for. See {@link HumanEntity#openInventory(InventoryView)}
+         * for more information.
+         *
+         * @param player the player the view belongs to
+         * @return the created {@link InventoryView}
+         */
+        default V create(HumanEntity player) {
+            return create(player, (Component) null);
+        }
+
         /**
          * Creates a view of the specified menu type.
          * <p>
@@ -148,11 +165,10 @@ public interface MenuType extends Keyed, io.papermc.paper.world.flag.FeatureDepe
          * @param player the player the view belongs to
          * @param title the title of the view
          * @return the created {@link InventoryView}
-         * @deprecated Use {@link #create(HumanEntity, net.kyori.adventure.text.Component)} instead.
+         * @deprecated Use {@link #create(HumanEntity, Component)} instead.
          */
-        @NotNull
         @Deprecated(since = "1.21") // Paper - adventure
-        V create(@NotNull HumanEntity player, @NotNull String title);
+        V create(HumanEntity player, @Nullable String title);
 
         // Paper start - adventure
         /**
@@ -166,11 +182,9 @@ public interface MenuType extends Keyed, io.papermc.paper.world.flag.FeatureDepe
          * @param title the title of the view
          * @return the created {@link InventoryView}
          */
-        @NotNull
-        V create(@NotNull HumanEntity player, @NotNull net.kyori.adventure.text.Component title);
+        V create(HumanEntity player, @Nullable Component title);
         // Paper end - adventure
 
-        @NotNull
         B builder();
     }
 
@@ -186,8 +200,7 @@ public interface MenuType extends Keyed, io.papermc.paper.world.flag.FeatureDepe
      * @param title the title of the view
      * @return the created {@link InventoryView}
      */
-    @NotNull
-    InventoryView create(@NotNull HumanEntity player, @NotNull net.kyori.adventure.text.Component title);
+    InventoryView create(HumanEntity player, @Nullable Component title);
     // Paper end - adventure
 
     /**
@@ -196,7 +209,6 @@ public interface MenuType extends Keyed, io.papermc.paper.world.flag.FeatureDepe
      *
      * @return the typed MenuType.
      */
-    @NotNull
     MenuType.Typed<InventoryView, InventoryViewBuilder<InventoryView>> typed();
 
     /**
@@ -213,19 +225,16 @@ public interface MenuType extends Keyed, io.papermc.paper.world.flag.FeatureDepe
      * @throws IllegalArgumentException if the provided viewClass cannot be
      * typed to this MenuType
      */
-    @NotNull
-    <V extends InventoryView, B extends InventoryViewBuilder<V>> MenuType.Typed<V, B> typed(@NotNull final Class<V> viewClass) throws IllegalArgumentException;
+    <V extends InventoryView, B extends InventoryViewBuilder<V>> MenuType.Typed<V, B> typed(final Class<V> viewClass) throws IllegalArgumentException;
 
     /**
      * Gets the {@link InventoryView} class of this MenuType.
      *
      * @return the {@link InventoryView} class of this MenuType
      */
-    @NotNull
     Class<? extends InventoryView> getInventoryViewClass();
 
-    @NotNull
-    private static <T extends MenuType> T get(@NotNull final String key) {
+    private static <T extends MenuType> T get(final String key) {
         return (T) Registry.MENU.getOrThrow(NamespacedKey.minecraft(key));
     }
 }
diff --git a/paper-api/src/main/java/org/bukkit/inventory/view/builder/InventoryViewBuilder.java b/paper-api/src/main/java/org/bukkit/inventory/view/builder/InventoryViewBuilder.java
index 9f07522283..28e52e7da2 100644
--- a/paper-api/src/main/java/org/bukkit/inventory/view/builder/InventoryViewBuilder.java
+++ b/paper-api/src/main/java/org/bukkit/inventory/view/builder/InventoryViewBuilder.java
@@ -4,6 +4,7 @@ import net.kyori.adventure.text.Component;
 import org.bukkit.entity.HumanEntity;
 import org.bukkit.inventory.InventoryView;
 import org.jetbrains.annotations.ApiStatus;
+import org.jspecify.annotations.Nullable;
 
 /**
  * Generic Builder for InventoryView's with no special attributes or parameters
@@ -23,10 +24,10 @@ public interface InventoryViewBuilder<V extends InventoryView> {
     /**
      * Sets the title of the builder
      *
-     * @param title the title
+     * @param title the title, or null for a default title
      * @return this builder
      */
-    InventoryViewBuilder<V> title(final Component title);
+    InventoryViewBuilder<V> title(@Nullable final Component title);
 
     /**
      * Builds this builder into a InventoryView
diff --git a/paper-api/src/main/java/org/bukkit/inventory/view/builder/LocationInventoryViewBuilder.java b/paper-api/src/main/java/org/bukkit/inventory/view/builder/LocationInventoryViewBuilder.java
index 9666aa3569..a532497277 100644
--- a/paper-api/src/main/java/org/bukkit/inventory/view/builder/LocationInventoryViewBuilder.java
+++ b/paper-api/src/main/java/org/bukkit/inventory/view/builder/LocationInventoryViewBuilder.java
@@ -4,7 +4,7 @@ import net.kyori.adventure.text.Component;
 import org.bukkit.Location;
 import org.bukkit.inventory.InventoryView;
 import org.jetbrains.annotations.ApiStatus;
-import org.jetbrains.annotations.NotNull;
+import org.jspecify.annotations.Nullable;
 
 /**
  * An InventoryViewBuilder that can be bound by location within the world
@@ -18,7 +18,7 @@ public interface LocationInventoryViewBuilder<V extends InventoryView> extends I
     LocationInventoryViewBuilder<V> copy();
 
     @Override
-    LocationInventoryViewBuilder<V> title(final @NotNull Component title);
+    LocationInventoryViewBuilder<V> title(final @Nullable Component title);
 
     /**
      * Determines whether or not the server should check if the player can reach
diff --git a/paper-api/src/main/java/org/bukkit/inventory/view/builder/MerchantInventoryViewBuilder.java b/paper-api/src/main/java/org/bukkit/inventory/view/builder/MerchantInventoryViewBuilder.java
index 76aecb54a9..a8e4e9f18f 100644
--- a/paper-api/src/main/java/org/bukkit/inventory/view/builder/MerchantInventoryViewBuilder.java
+++ b/paper-api/src/main/java/org/bukkit/inventory/view/builder/MerchantInventoryViewBuilder.java
@@ -5,7 +5,7 @@ import org.bukkit.Server;
 import org.bukkit.inventory.InventoryView;
 import org.bukkit.inventory.Merchant;
 import org.jetbrains.annotations.ApiStatus;
-import org.jetbrains.annotations.NotNull;
+import org.jspecify.annotations.Nullable;
 
 /**
  * An InventoryViewBuilder for creating merchant views
@@ -19,7 +19,7 @@ public interface MerchantInventoryViewBuilder<V extends InventoryView> extends I
     MerchantInventoryViewBuilder<V> copy();
 
     @Override
-    MerchantInventoryViewBuilder<V> title(final @NotNull Component title);
+    MerchantInventoryViewBuilder<V> title(final @Nullable Component title);
 
     /**
      * Adds a merchant to this builder
diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/ChestBlock.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/ChestBlock.java.patch
index 5ec5cd486d..7b27fcf641 100644
--- a/paper-server/patches/sources/net/minecraft/world/level/block/ChestBlock.java.patch
+++ b/paper-server/patches/sources/net/minecraft/world/level/block/ChestBlock.java.patch
@@ -9,8 +9,12 @@
                  @Nullable
                  @Override
                  public AbstractContainerMenu createMenu(int containerId, Inventory playerInventory, Player player) {
-@@ -106,7 +_,7 @@
-                         return (Component)(second.hasCustomName() ? second.getDisplayName() : Component.translatable("container.chestDouble"));
+@@ -103,10 +_,10 @@
+                     if (first.hasCustomName()) {
+                         return first.getDisplayName();
+                     } else {
+-                        return (Component)(second.hasCustomName() ? second.getDisplayName() : Component.translatable("container.chestDouble"));
++                        return (Component)(second.hasCustomName() ? second.getDisplayName() : Component.translatable("container.chestDouble")); // Paper - diff on change - CraftDoubleChestInventoryViewBuilder.defaultTitle
                      }
                  }
 -            });
diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/entity/ChestBlockEntity.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/entity/ChestBlockEntity.java.patch
index 32a967c2c3..b8ba6305b2 100644
--- a/paper-server/patches/sources/net/minecraft/world/level/block/entity/ChestBlockEntity.java.patch
+++ b/paper-server/patches/sources/net/minecraft/world/level/block/entity/ChestBlockEntity.java.patch
@@ -37,3 +37,12 @@
      protected ChestBlockEntity(BlockEntityType<?> type, BlockPos pos, BlockState blockState) {
          super(type, pos, blockState);
      }
+@@ -71,7 +_,7 @@
+ 
+     @Override
+     protected Component getDefaultName() {
+-        return Component.translatable("container.chest");
++        return Component.translatable("container.chest"); // Paper - diff on change - CraftStandardInventoryViewBuilder.defaultTitle
+     }
+ 
+     @Override
diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/paper-server/src/main/java/org/bukkit/craftbukkit/CraftServer.java
index cf5bcb0ebc..59eddee7e7 100644
--- a/paper-server/src/main/java/org/bukkit/craftbukkit/CraftServer.java
+++ b/paper-server/src/main/java/org/bukkit/craftbukkit/CraftServer.java
@@ -2479,7 +2479,7 @@ public final class CraftServer implements Server {
 
     @Override
     public @NotNull Merchant createMerchant() {
-        return new CraftMerchantCustom(net.kyori.adventure.text.Component.empty());
+        return new CraftMerchantCustom();
     }
 
     @Override
diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftMenuType.java b/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftMenuType.java
index 4c6cf43cee..326b62c859 100644
--- a/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftMenuType.java
+++ b/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftMenuType.java
@@ -38,7 +38,7 @@ public class CraftMenuType<V extends InventoryView, B extends InventoryViewBuild
     @Override
     public V create(final HumanEntity player, final String title) {
     // Paper start - adventure
-        return builder().title(net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserialize(title)).build(player);
+        return builder().title(title != null ? net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserialize(title) : null).build(player);
     }
     @Override
     public V create(final HumanEntity player, final net.kyori.adventure.text.Component title) {
diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftMerchantCustom.java b/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftMerchantCustom.java
index d9f9d4abae..3572e98f47 100644
--- a/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftMerchantCustom.java
+++ b/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftMerchantCustom.java
@@ -4,6 +4,7 @@ import com.google.common.base.Preconditions;
 import net.minecraft.network.chat.Component;
 import net.minecraft.sounds.SoundEvent;
 import net.minecraft.sounds.SoundEvents;
+import net.minecraft.world.entity.EntityType;
 import net.minecraft.world.entity.player.Player;
 import net.minecraft.world.item.ItemStack;
 import net.minecraft.world.item.trading.Merchant;
@@ -25,6 +26,11 @@ public class CraftMerchantCustom implements CraftMerchant {
         this.merchant = new MinecraftMerchant(title);
         getMerchant().craftMerchant = this;
     }
+
+    public CraftMerchantCustom() {
+        this.merchant = new MinecraftMerchant();
+        getMerchant().craftMerchant = this;
+    }
     // Paper end
 
     @Override
@@ -54,6 +60,10 @@ public class CraftMerchantCustom implements CraftMerchant {
             Preconditions.checkArgument(title != null, "Title cannot be null");
             this.title = io.papermc.paper.adventure.PaperAdventure.asVanilla(title);
         }
+
+        public MinecraftMerchant() {
+            this.title = EntityType.VILLAGER.getDescription();
+        }
         // Paper end
 
         @Override
diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/util/CraftMenus.java b/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/util/CraftMenus.java
index 84c35792c4..0224aedbdf 100644
--- a/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/util/CraftMenus.java
+++ b/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/util/CraftMenus.java
@@ -17,6 +17,7 @@ import net.minecraft.world.level.block.Blocks;
 import net.minecraft.world.level.block.entity.BeaconBlockEntity;
 import net.minecraft.world.level.block.entity.BlastFurnaceBlockEntity;
 import net.minecraft.world.level.block.entity.BrewingStandBlockEntity;
+import net.minecraft.world.level.block.entity.ChestBlockEntity;
 import net.minecraft.world.level.block.entity.CrafterBlockEntity;
 import net.minecraft.world.level.block.entity.DispenserBlockEntity;
 import net.minecraft.world.level.block.entity.FurnaceBlockEntity;
@@ -29,6 +30,7 @@ import org.bukkit.craftbukkit.inventory.CraftMerchant;
 import org.bukkit.craftbukkit.inventory.view.builder.CraftAccessLocationInventoryViewBuilder;
 import org.bukkit.craftbukkit.inventory.view.builder.CraftBlockEntityInventoryViewBuilder;
 import org.bukkit.craftbukkit.inventory.view.builder.CraftDoubleChestInventoryViewBuilder;
+import org.bukkit.craftbukkit.inventory.view.builder.CraftEnchantmentInventoryViewBuilder;
 import org.bukkit.craftbukkit.inventory.view.builder.CraftMerchantInventoryViewBuilder;
 import org.bukkit.craftbukkit.inventory.view.builder.CraftStandardInventoryViewBuilder;
 import org.bukkit.inventory.InventoryView;
@@ -87,7 +89,7 @@ public final class CraftMenus {
             return asType(new MenuTypeData<>(InventoryView.class, () -> new CraftDoubleChestInventoryViewBuilder<>(handle)));
         }
         if (menuType == MenuType.GENERIC_9X3) {
-            return asType(new MenuTypeData<>(InventoryView.class, () -> new CraftBlockEntityInventoryViewBuilder<>(handle, Blocks.CHEST, null)));
+            return asType(new MenuTypeData<>(InventoryView.class, () -> new CraftBlockEntityInventoryViewBuilder<>(handle, Blocks.CHEST, ChestBlockEntity::new, false)));
         }
         // this isn't ideal as both dispenser and dropper are 3x3, InventoryType can't currently handle generic 3x3s with size 9
         // this needs to be removed when inventory creation is overhauled
@@ -98,7 +100,7 @@ public final class CraftMenus {
             return asType(new MenuTypeData<>(CrafterView.class, () -> new CraftBlockEntityInventoryViewBuilder<>(handle, Blocks.CRAFTER, CrafterBlockEntity::new)));
         }
         if (menuType == MenuType.ANVIL) {
-            return asType(new MenuTypeData<>(AnvilView.class, () -> new CraftAccessLocationInventoryViewBuilder<>(handle, AnvilMenu::new)));
+            return asType(new MenuTypeData<>(AnvilView.class, () -> new CraftAccessLocationInventoryViewBuilder<>(handle, Blocks.ANVIL)));
         }
         if (menuType == MenuType.BEACON) {
             return asType(new MenuTypeData<>(BeaconView.class, () -> new CraftBlockEntityInventoryViewBuilder<>(handle, Blocks.BEACON, BeaconBlockEntity::new)));
@@ -110,16 +112,16 @@ public final class CraftMenus {
             return asType(new MenuTypeData<>(BrewingStandView.class, () -> new CraftBlockEntityInventoryViewBuilder<>(handle, Blocks.BREWING_STAND, BrewingStandBlockEntity::new)));
         }
         if (menuType == MenuType.CRAFTING) {
-            return asType(new MenuTypeData<>(InventoryView.class, () -> new CraftAccessLocationInventoryViewBuilder<>(handle, CraftingMenu::new)));
+            return asType(new MenuTypeData<>(InventoryView.class, () -> new CraftAccessLocationInventoryViewBuilder<>(handle, Blocks.CRAFTING_TABLE)));
         }
         if (menuType == MenuType.ENCHANTMENT) {
-            return asType(new MenuTypeData<>(EnchantmentView.class, () -> new CraftAccessLocationInventoryViewBuilder<>(handle, EnchantmentMenu::new)));
+            return asType(new MenuTypeData<>(EnchantmentView.class, () -> new CraftEnchantmentInventoryViewBuilder(handle)));
         }
         if (menuType == MenuType.FURNACE) {
             return asType(new MenuTypeData<>(FurnaceView.class, () -> new CraftBlockEntityInventoryViewBuilder<>(handle, Blocks.FURNACE, FurnaceBlockEntity::new)));
         }
         if (menuType == MenuType.GRINDSTONE) {
-            return asType(new MenuTypeData<>(InventoryView.class, () -> new CraftAccessLocationInventoryViewBuilder<>(handle, GrindstoneMenu::new)));
+            return asType(new MenuTypeData<>(InventoryView.class, () -> new CraftAccessLocationInventoryViewBuilder<>(handle, Blocks.GRINDSTONE)));
         }
         // We really don't need to be creating a tile entity for hopper but currently InventoryType doesn't have capacity
         // to understand otherwise
@@ -131,7 +133,7 @@ public final class CraftMenus {
             return asType(new MenuTypeData<>(LecternView.class, () -> new CraftBlockEntityInventoryViewBuilder<>(handle, Blocks.LECTERN, LecternBlockEntity::new)));
         }
         if (menuType == MenuType.LOOM) {
-            return asType(new MenuTypeData<>(LoomView.class, () -> new CraftStandardInventoryViewBuilder<>(handle)));
+            return asType(new MenuTypeData<>(LoomView.class, () -> new CraftAccessLocationInventoryViewBuilder<>(handle, Blocks.LOOM)));
         }
         if (menuType == MenuType.MERCHANT) {
             return asType(new MenuTypeData<>(MerchantView.class, () -> new CraftMerchantInventoryViewBuilder<>(handle)));
@@ -140,16 +142,16 @@ public final class CraftMenus {
             return asType(new MenuTypeData<>(InventoryView.class, () -> new CraftBlockEntityInventoryViewBuilder<>(handle, Blocks.SHULKER_BOX, ShulkerBoxBlockEntity::new)));
         }
         if (menuType == MenuType.SMITHING) {
-            return asType(new MenuTypeData<>(InventoryView.class, () -> new CraftAccessLocationInventoryViewBuilder<>(handle, SmithingMenu::new)));
+            return asType(new MenuTypeData<>(InventoryView.class, () -> new CraftAccessLocationInventoryViewBuilder<>(handle, Blocks.SMITHING_TABLE)));
         }
         if (menuType == MenuType.SMOKER) {
             return asType(new MenuTypeData<>(FurnaceView.class, () -> new CraftBlockEntityInventoryViewBuilder<>(handle, Blocks.SMOKER, SmokerBlockEntity::new)));
         }
         if (menuType == MenuType.CARTOGRAPHY_TABLE) {
-            return asType(new MenuTypeData<>(InventoryView.class, () -> new CraftAccessLocationInventoryViewBuilder<>(handle, CartographyTableMenu::new)));
+            return asType(new MenuTypeData<>(InventoryView.class, () -> new CraftAccessLocationInventoryViewBuilder<>(handle, Blocks.CARTOGRAPHY_TABLE)));
         }
         if (menuType == MenuType.STONECUTTER) {
-            return asType(new MenuTypeData<>(StonecutterView.class, () -> new CraftAccessLocationInventoryViewBuilder<>(handle, StonecutterMenu::new)));
+            return asType(new MenuTypeData<>(StonecutterView.class, () -> new CraftAccessLocationInventoryViewBuilder<>(handle, Blocks.STONECUTTER)));
         }
 
         return asType(new MenuTypeData<>(InventoryView.class, () -> new CraftStandardInventoryViewBuilder<>(handle)));
diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/view/builder/CraftAbstractInventoryViewBuilder.java b/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/view/builder/CraftAbstractInventoryViewBuilder.java
index 185ad0fc16..ef1abf7bfa 100644
--- a/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/view/builder/CraftAbstractInventoryViewBuilder.java
+++ b/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/view/builder/CraftAbstractInventoryViewBuilder.java
@@ -10,21 +10,22 @@ import org.bukkit.craftbukkit.entity.CraftHumanEntity;
 import org.bukkit.entity.HumanEntity;
 import org.bukkit.inventory.InventoryView;
 import org.bukkit.inventory.view.builder.InventoryViewBuilder;
-import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
+import org.jspecify.annotations.Nullable;
 
 public abstract class CraftAbstractInventoryViewBuilder<V extends InventoryView> implements InventoryViewBuilder<V> {
 
     protected final MenuType<?> handle;
 
     protected boolean checkReachable = false;
-    protected @MonotonicNonNull Component title = null;
+    protected @Nullable Component title = null;
+    protected net.minecraft.network.chat.Component defaultTitle = null;
 
     public CraftAbstractInventoryViewBuilder(final MenuType<?> handle) {
         this.handle = handle;
     }
 
     @Override
-    public InventoryViewBuilder<V> title(final Component title) {
+    public InventoryViewBuilder<V> title(final @Nullable Component title) {
         this.title = title;
         return this;
     }
@@ -33,14 +34,14 @@ public abstract class CraftAbstractInventoryViewBuilder<V extends InventoryView>
     @Override
     public V build(final HumanEntity player) {
         Preconditions.checkArgument(player != null, "The given player must not be null");
-        Preconditions.checkArgument(this.title != null, "The given title must not be null");
         Preconditions.checkArgument(player instanceof CraftHumanEntity, "The given player must be a CraftHumanEntity");
         final CraftHumanEntity craftHuman = (CraftHumanEntity) player;
-        Preconditions.checkArgument(craftHuman.getHandle() instanceof ServerPlayer, "The given player must be an EntityPlayer");
+        Preconditions.checkArgument(craftHuman.getHandle() instanceof ServerPlayer, "The given player must be an ServerPlayer");
         final ServerPlayer serverPlayer = (ServerPlayer) craftHuman.getHandle();
+
         final AbstractContainerMenu container = buildContainer(serverPlayer);
         container.checkReachable = this.checkReachable;
-        container.setTitle(PaperAdventure.asVanilla(this.title));
+        container.setTitle(this.title != null ? PaperAdventure.asVanilla(this.title) : this.defaultTitle);
         return (V) container.getBukkitView();
     }
 
diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/view/builder/CraftAbstractLocationInventoryViewBuilder.java b/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/view/builder/CraftAbstractLocationInventoryViewBuilder.java
index 7a894ca078..15f1b30160 100644
--- a/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/view/builder/CraftAbstractLocationInventoryViewBuilder.java
+++ b/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/view/builder/CraftAbstractLocationInventoryViewBuilder.java
@@ -22,7 +22,7 @@ public abstract class CraftAbstractLocationInventoryViewBuilder<V extends Invent
     }
 
     @Override
-    public LocationInventoryViewBuilder<V> title(final Component title) {
+    public LocationInventoryViewBuilder<V> title(final @Nullable Component title) {
         return (LocationInventoryViewBuilder<V>) super.title(title);
     }
 
diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/view/builder/CraftAccessLocationInventoryViewBuilder.java b/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/view/builder/CraftAccessLocationInventoryViewBuilder.java
index 096f3ebf81..8e0d453199 100644
--- a/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/view/builder/CraftAccessLocationInventoryViewBuilder.java
+++ b/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/view/builder/CraftAccessLocationInventoryViewBuilder.java
@@ -1,37 +1,50 @@
 package org.bukkit.craftbukkit.inventory.view.builder;
 
+import net.minecraft.core.BlockPos;
 import net.minecraft.server.level.ServerPlayer;
+import net.minecraft.world.MenuProvider;
 import net.minecraft.world.entity.player.Inventory;
 import net.minecraft.world.inventory.AbstractContainerMenu;
 import net.minecraft.world.inventory.ContainerLevelAccess;
 import net.minecraft.world.inventory.MenuType;
+import net.minecraft.world.level.Level;
+import net.minecraft.world.level.block.Block;
+import net.minecraft.world.level.block.state.BlockState;
 import org.bukkit.inventory.InventoryView;
 import org.bukkit.inventory.view.builder.LocationInventoryViewBuilder;
 
 public class CraftAccessLocationInventoryViewBuilder<V extends InventoryView> extends CraftAbstractLocationInventoryViewBuilder<V> {
 
-    private final CraftAccessContainerObjectBuilder containerBuilder;
+    private final Block block;
 
-    public CraftAccessLocationInventoryViewBuilder(final MenuType<?> handle, final CraftAccessContainerObjectBuilder containerBuilder) {
+    public CraftAccessLocationInventoryViewBuilder(final MenuType<?> handle, final Block block) {
         super(handle);
-        this.containerBuilder = containerBuilder;
+        this.block = block;
     }
 
     @Override
     protected AbstractContainerMenu buildContainer(final ServerPlayer player) {
-        final ContainerLevelAccess access;
-        if (super.position == null) {
-            access = ContainerLevelAccess.create(player.level(), player.blockPosition());
+        final BlockState effectiveBlockState;
+        final BlockPos effectiveBlockPos;
+        final Level effectiveLevel;
+        if (super.position != null) {
+            effectiveBlockPos = super.position;
+            effectiveLevel = super.world;
+            effectiveBlockState = super.world.getBlockState(position);
         } else {
-            access = ContainerLevelAccess.create(super.world, super.position);
+            effectiveBlockPos = player.blockPosition();
+            effectiveLevel = player.level();
+            effectiveBlockState = block.defaultBlockState();
         }
 
-        return this.containerBuilder.build(player.nextContainerCounter(), player.getInventory(), access);
+        final MenuProvider provider = block.getMenuProvider(effectiveBlockState, effectiveLevel, effectiveBlockPos);
+        super.defaultTitle = provider.getDisplayName();
+        return provider.createMenu(player.nextContainerCounter(), player.getInventory(), player);
     }
 
     @Override
     public LocationInventoryViewBuilder<V> copy() {
-        final CraftAccessLocationInventoryViewBuilder<V> copy = new CraftAccessLocationInventoryViewBuilder<>(this.handle, this.containerBuilder);
+        final CraftAccessLocationInventoryViewBuilder<V> copy = new CraftAccessLocationInventoryViewBuilder<>(this.handle, this.block);
         copy.world = super.world;
         copy.position = super.position;
         copy.checkReachable = super.checkReachable;
diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/view/builder/CraftBlockEntityInventoryViewBuilder.java b/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/view/builder/CraftBlockEntityInventoryViewBuilder.java
index 2625814440..b555d5078d 100644
--- a/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/view/builder/CraftBlockEntityInventoryViewBuilder.java
+++ b/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/view/builder/CraftBlockEntityInventoryViewBuilder.java
@@ -16,10 +16,25 @@ import org.jspecify.annotations.Nullable;
 public class CraftBlockEntityInventoryViewBuilder<V extends InventoryView> extends CraftAbstractLocationInventoryViewBuilder<V> {
 
     private final Block block;
-    private final @Nullable CraftTileInventoryBuilder builder;
+    private final boolean useFakeBlockEntity;
+    private final @Nullable CraftBlockInventoryBuilder builder;
 
-    public CraftBlockEntityInventoryViewBuilder(final MenuType<?> handle, final Block block, final @Nullable CraftTileInventoryBuilder builder) {
+    public CraftBlockEntityInventoryViewBuilder(
+        final MenuType<?> handle,
+        final Block block,
+        final @Nullable CraftBlockInventoryBuilder builder
+    ) {
+        this(handle, block, builder, true);
+    }
+
+    public CraftBlockEntityInventoryViewBuilder(
+        final MenuType<?> handle,
+        final Block block,
+        final @Nullable CraftBlockInventoryBuilder builder,
+        final boolean useFakeBlockEntity
+    ) {
         super(handle);
+        this.useFakeBlockEntity = useFakeBlockEntity;
         this.block = block;
         this.builder = builder;
     }
@@ -32,35 +47,44 @@ public class CraftBlockEntityInventoryViewBuilder<V extends InventoryView> exten
 
         if (this.position == null) {
             this.position = player.blockPosition();
+            return buildFakeBlockEntity(player);
         }
 
         final BlockEntity entity = this.world.getBlockEntity(position);
         if (!(entity instanceof final MenuConstructor container)) {
-            return buildFakeTile(player);
+            return buildFakeBlockEntity(player);
         }
 
         final AbstractContainerMenu atBlock = container.createMenu(player.nextContainerCounter(), player.getInventory(), player);
         if (atBlock.getType() != super.handle) {
-            return buildFakeTile(player);
+            return buildFakeBlockEntity(player);
         }
 
+        if (!(entity instanceof final MenuProvider provider)) {
+            throw new IllegalStateException("Provided blockEntity during MenuType creation can not find a default title! This is a bug!");
+        }
+
+        super.defaultTitle = provider.getDisplayName();
         return atBlock;
     }
 
-    private AbstractContainerMenu buildFakeTile(final ServerPlayer player) {
-        if (this.builder == null) {
+    private AbstractContainerMenu buildFakeBlockEntity(final ServerPlayer player) {
+        final MenuProvider inventory = this.builder.build(this.position, this.block.defaultBlockState());
+        if (inventory instanceof final BlockEntity blockEntity) {
+            blockEntity.setLevel(this.world);
+            super.defaultTitle = inventory.getDisplayName();
+        }
+
+        if (!this.useFakeBlockEntity) { // gets around open noise for chest
             return handle.create(player.nextContainerCounter(), player.getInventory());
         }
-        final MenuProvider inventory = this.builder.build(this.position, this.block.defaultBlockState());
-        if (inventory instanceof final BlockEntity tile) {
-            tile.setLevel(this.world);
-        }
+
         return inventory.createMenu(player.nextContainerCounter(), player.getInventory(), player);
     }
 
     @Override
     public LocationInventoryViewBuilder<V> copy() {
-        final CraftBlockEntityInventoryViewBuilder<V> copy = new CraftBlockEntityInventoryViewBuilder<>(super.handle, this.block, this.builder);
+        final CraftBlockEntityInventoryViewBuilder<V> copy = new CraftBlockEntityInventoryViewBuilder<>(super.handle, this.block, this.builder, this.useFakeBlockEntity);
         copy.world = this.world;
         copy.position = this.position;
         copy.checkReachable = super.checkReachable;
@@ -68,7 +92,7 @@ public class CraftBlockEntityInventoryViewBuilder<V extends InventoryView> exten
         return copy;
     }
 
-    public interface CraftTileInventoryBuilder {
+    public interface CraftBlockInventoryBuilder {
         MenuProvider build(BlockPos blockPosition, BlockState blockData);
     }
 }
diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/view/builder/CraftDoubleChestInventoryViewBuilder.java b/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/view/builder/CraftDoubleChestInventoryViewBuilder.java
index 331e3797a5..f0133272dd 100644
--- a/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/view/builder/CraftDoubleChestInventoryViewBuilder.java
+++ b/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/view/builder/CraftDoubleChestInventoryViewBuilder.java
@@ -1,5 +1,6 @@
 package org.bukkit.craftbukkit.inventory.view.builder;
 
+import net.minecraft.network.chat.Component;
 import net.minecraft.server.level.ServerPlayer;
 import net.minecraft.world.MenuProvider;
 import net.minecraft.world.inventory.AbstractContainerMenu;
@@ -15,6 +16,7 @@ public class CraftDoubleChestInventoryViewBuilder<V extends InventoryView> exten
 
     public CraftDoubleChestInventoryViewBuilder(final MenuType<?> handle) {
         super(handle);
+        super.defaultTitle = Component.translatable("container.chestDouble");
     }
 
     @Override
@@ -24,7 +26,9 @@ public class CraftDoubleChestInventoryViewBuilder<V extends InventoryView> exten
         }
 
         final ChestBlock chest = (ChestBlock) Blocks.CHEST;
-        final DoubleBlockCombiner.NeighborCombineResult<? extends ChestBlockEntity> result = chest.combine(super.world.getBlockState(super.position), super.world, super.position, false);
+        final DoubleBlockCombiner.NeighborCombineResult<? extends ChestBlockEntity> result = chest.combine(
+            super.world.getBlockState(super.position), super.world, super.position, false
+        );
         if (result instanceof DoubleBlockCombiner.NeighborCombineResult.Single<? extends ChestBlockEntity>) {
             return handle.create(player.nextContainerCounter(), player.getInventory());
         }
@@ -33,6 +37,7 @@ public class CraftDoubleChestInventoryViewBuilder<V extends InventoryView> exten
         if (combined == null) {
             return handle.create(player.nextContainerCounter(), player.getInventory());
         }
+
         return combined.createMenu(player.nextContainerCounter(), player.getInventory(), player);
     }
 
diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/view/builder/CraftEnchantmentInventoryViewBuilder.java b/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/view/builder/CraftEnchantmentInventoryViewBuilder.java
new file mode 100644
index 0000000000..6f50294159
--- /dev/null
+++ b/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/view/builder/CraftEnchantmentInventoryViewBuilder.java
@@ -0,0 +1,40 @@
+package org.bukkit.craftbukkit.inventory.view.builder;
+
+import net.minecraft.server.level.ServerPlayer;
+import net.minecraft.world.inventory.AbstractContainerMenu;
+import net.minecraft.world.inventory.ContainerLevelAccess;
+import net.minecraft.world.inventory.EnchantmentMenu;
+import net.minecraft.world.inventory.MenuType;
+import net.minecraft.world.level.block.Blocks;
+import net.minecraft.world.level.block.entity.BlockEntity;
+import net.minecraft.world.level.block.entity.EnchantingTableBlockEntity;
+import org.bukkit.inventory.view.EnchantmentView;
+
+public class CraftEnchantmentInventoryViewBuilder extends CraftAbstractLocationInventoryViewBuilder<EnchantmentView> {
+
+    public CraftEnchantmentInventoryViewBuilder(final MenuType<?> handle) {
+        super(handle);
+    }
+
+    @Override
+    protected AbstractContainerMenu buildContainer(final ServerPlayer player) {
+        if (this.world == null) {
+            this.world = player.level();
+        }
+
+        if (this.position == null) {
+            this.position = player.blockPosition();
+            super.defaultTitle = new EnchantingTableBlockEntity(this.position, Blocks.ENCHANTING_TABLE.defaultBlockState()).getDisplayName();
+            return new EnchantmentMenu(player.nextContainerCounter(), player.getInventory(), ContainerLevelAccess.create(this.world, this.position));
+        }
+
+        final BlockEntity entity = this.world.getBlockEntity(position);
+        if (entity instanceof final EnchantingTableBlockEntity enchantingBlockEntity) {
+            super.defaultTitle = enchantingBlockEntity.getDisplayName();
+        } else {
+            super.defaultTitle = new EnchantingTableBlockEntity(this.position, Blocks.ENCHANTING_TABLE.defaultBlockState()).getDisplayName();
+        }
+
+        return new EnchantmentMenu(player.nextContainerCounter(), player.getInventory(), ContainerLevelAccess.create(this.world, this.position));
+    }
+}
diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/view/builder/CraftMerchantInventoryViewBuilder.java b/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/view/builder/CraftMerchantInventoryViewBuilder.java
index 7f7518aa73..d46f942e1c 100644
--- a/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/view/builder/CraftMerchantInventoryViewBuilder.java
+++ b/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/view/builder/CraftMerchantInventoryViewBuilder.java
@@ -4,6 +4,7 @@ import com.google.common.base.Preconditions;
 import io.papermc.paper.adventure.PaperAdventure;
 import net.kyori.adventure.text.Component;
 import net.minecraft.server.level.ServerPlayer;
+import net.minecraft.world.entity.npc.AbstractVillager;
 import net.minecraft.world.inventory.AbstractContainerMenu;
 import net.minecraft.world.inventory.MenuType;
 import net.minecraft.world.inventory.MerchantMenu;
@@ -25,7 +26,7 @@ public class CraftMerchantInventoryViewBuilder<V extends InventoryView> extends
     }
 
     @Override
-    public MerchantInventoryViewBuilder<V> title(final Component title) {
+    public MerchantInventoryViewBuilder<V> title(final @Nullable Component title) {
         return (MerchantInventoryViewBuilder<V>) super.title(title);
     }
 
@@ -44,24 +45,34 @@ public class CraftMerchantInventoryViewBuilder<V extends InventoryView> extends
     @Override
     public V build(final HumanEntity player) {
         Preconditions.checkArgument(player != null, "The given player must not be null");
-        Preconditions.checkArgument(this.title != null, "The given title must not be null");
         Preconditions.checkArgument(player instanceof CraftHumanEntity, "The given player must be a CraftHumanEntity");
         final CraftHumanEntity craftHuman = (CraftHumanEntity) player;
-        Preconditions.checkArgument(craftHuman.getHandle() instanceof ServerPlayer, "The given player must be an EntityPlayer");
+        Preconditions.checkArgument(craftHuman.getHandle() instanceof ServerPlayer, "The given player must be an ServerPlayer");
         final ServerPlayer serverPlayer = (ServerPlayer) craftHuman.getHandle();
 
         final MerchantMenu container;
         if (this.merchant == null) {
-            container = new MerchantMenu(serverPlayer.nextContainerCounter(), serverPlayer.getInventory(), new CraftMerchantCustom(title).getMerchant());
-        } else {
-            container = new MerchantMenu(serverPlayer.nextContainerCounter(), serverPlayer.getInventory(), this.merchant);
+            this.merchant = this.title == null ? new CraftMerchantCustom().getMerchant() : new CraftMerchantCustom(title).getMerchant();
         }
 
+        container = new MerchantMenu(serverPlayer.nextContainerCounter(), serverPlayer.getInventory(), this.merchant);
+
         container.checkReachable = super.checkReachable;
-        container.setTitle(PaperAdventure.asVanilla(this.title));
+        setDefaultTitle(this.merchant);
+        container.setTitle(super.title != null ? PaperAdventure.asVanilla(this.title) : super.defaultTitle);
         return (V) container.getBukkitView();
     }
 
+    private void setDefaultTitle(final net.minecraft.world.item.trading.Merchant merchant) {
+        if (merchant instanceof final AbstractVillager villager) {
+            super.defaultTitle = villager.getDisplayName();
+        } else if (merchant instanceof final CraftMerchantCustom.MinecraftMerchant custom) {
+            super.defaultTitle = custom.getScoreboardDisplayName();
+        } else {
+            throw new IllegalStateException("Provided merchant during MenuType creation can not find a default title! This is a bug!");
+        }
+    }
+
     @Override
     protected AbstractContainerMenu buildContainer(final ServerPlayer player) {
         throw new UnsupportedOperationException("buildContainer is not supported for CraftMerchantInventoryViewBuilder");
diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/view/builder/CraftStandardInventoryViewBuilder.java b/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/view/builder/CraftStandardInventoryViewBuilder.java
index e528facbe0..670f79d008 100644
--- a/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/view/builder/CraftStandardInventoryViewBuilder.java
+++ b/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/view/builder/CraftStandardInventoryViewBuilder.java
@@ -1,5 +1,6 @@
 package org.bukkit.craftbukkit.inventory.view.builder;
 
+import net.minecraft.network.chat.Component;
 import net.minecraft.server.level.ServerPlayer;
 import net.minecraft.world.inventory.AbstractContainerMenu;
 import net.minecraft.world.inventory.MenuType;
@@ -10,6 +11,7 @@ public class CraftStandardInventoryViewBuilder<V extends InventoryView> extends
 
     public CraftStandardInventoryViewBuilder(final MenuType<?> handle) {
         super(handle);
+        super.defaultTitle = Component.translatable("container.chest");
     }
 
     @Override