diff --git a/nms-patches/TileEntityBrewingStand.patch b/nms-patches/TileEntityBrewingStand.patch
index 11833f9693..fe3d21e34d 100644
--- a/nms-patches/TileEntityBrewingStand.patch
+++ b/nms-patches/TileEntityBrewingStand.patch
@@ -1,6 +1,6 @@
 --- a/net/minecraft/server/TileEntityBrewingStand.java
 +++ b/net/minecraft/server/TileEntityBrewingStand.java
-@@ -3,6 +3,15 @@
+@@ -3,6 +3,16 @@
  import java.util.Arrays;
  import java.util.Iterator;
  
@@ -11,12 +11,13 @@
 +import org.bukkit.entity.HumanEntity;
 +import org.bukkit.event.inventory.BrewEvent;
 +import org.bukkit.event.inventory.BrewingStandFuelEvent;
++import org.bukkit.inventory.InventoryHolder;
 +// CraftBukkit end
 +
  public class TileEntityBrewingStand extends TileEntityContainer implements ITickable, IWorldInventory {
  
      private static final int[] a = new int[] { 3};
-@@ -14,6 +23,31 @@
+@@ -14,6 +24,31 @@
      private Item k;
      private String l;
      private int fuelLevel;
@@ -48,7 +49,7 @@
  
      public TileEntityBrewingStand() {
          this.items = NonNullList.a(5, ItemStack.a);
-@@ -55,8 +89,19 @@
+@@ -55,8 +90,19 @@
          ItemStack itemstack = (ItemStack) this.items.get(4);
  
          if (this.fuelLevel <= 0 && itemstack.getItem() == Items.BLAZE_POWDER) {
@@ -70,7 +71,7 @@
              this.update();
          }
  
-@@ -64,9 +109,14 @@
+@@ -64,9 +110,14 @@
          boolean flag1 = this.brewTime > 0;
          ItemStack itemstack1 = (ItemStack) this.items.get(3);
  
@@ -87,13 +88,14 @@
  
              if (flag2 && flag) {
                  this.p();
-@@ -140,6 +190,15 @@
+@@ -140,6 +191,16 @@
  
      private void p() {
          ItemStack itemstack = (ItemStack) this.items.get(3);
 +        // CraftBukkit start
-+        if (getOwner() != null) {
-+            BrewEvent event = new BrewEvent(world.getWorld().getBlockAt(position.getX(), position.getY(), position.getZ()), (org.bukkit.inventory.BrewerInventory) this.getOwner().getInventory(), this.fuelLevel);
++        InventoryHolder owner = this.getOwner();
++        if (owner != null) {
++            BrewEvent event = new BrewEvent(world.getWorld().getBlockAt(position.getX(), position.getY(), position.getZ()), (org.bukkit.inventory.BrewerInventory) owner.getInventory(), this.fuelLevel);
 +            org.bukkit.Bukkit.getPluginManager().callEvent(event);
 +            if (event.isCancelled()) {
 +                return;
@@ -103,7 +105,7 @@
  
          for (int i = 0; i < 3; ++i) {
              this.items.set(i, PotionBrewer.d(itemstack, (ItemStack) this.items.get(i)));
-@@ -210,7 +269,7 @@
+@@ -210,7 +271,7 @@
      }
  
      public int getMaxStackSize() {
diff --git a/nms-patches/TileEntityContainer.patch b/nms-patches/TileEntityContainer.patch
index 3484ee4f41..e49e2ca979 100644
--- a/nms-patches/TileEntityContainer.patch
+++ b/nms-patches/TileEntityContainer.patch
@@ -1,6 +1,6 @@
 --- a/net/minecraft/server/TileEntityContainer.java
 +++ b/net/minecraft/server/TileEntityContainer.java
-@@ -37,4 +37,11 @@
+@@ -37,4 +37,12 @@
      public IChatBaseComponent getScoreboardDisplayName() {
          return (IChatBaseComponent) (this.hasCustomName() ? new ChatComponentText(this.getName()) : new ChatMessage(this.getName(), new Object[0]));
      }
@@ -8,6 +8,7 @@
 +    // CraftBukkit start
 +    @Override
 +    public org.bukkit.Location getLocation() {
++        if (world == null) return null;
 +        return new org.bukkit.Location(world.getWorld(), position.getX(), position.getY(), position.getZ());
 +    }
 +    // CraftBukkit end
diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftBanner.java b/src/main/java/org/bukkit/craftbukkit/block/CraftBanner.java
index 7bf7269945..f374385e91 100644
--- a/src/main/java/org/bukkit/craftbukkit/block/CraftBanner.java
+++ b/src/main/java/org/bukkit/craftbukkit/block/CraftBanner.java
@@ -12,33 +12,23 @@ import org.bukkit.block.Banner;
 import org.bukkit.block.Block;
 import org.bukkit.block.banner.Pattern;
 import org.bukkit.block.banner.PatternType;
-import org.bukkit.craftbukkit.CraftWorld;
 
-public class CraftBanner extends CraftBlockState implements Banner {
+public class CraftBanner extends CraftBlockEntityState<TileEntityBanner> implements Banner {
 
-    private final TileEntityBanner banner;
     private DyeColor base;
     private List<Pattern> patterns = new ArrayList<Pattern>();
 
     public CraftBanner(final Block block) {
-        super(block);
-
-        CraftWorld world = (CraftWorld) block.getWorld();
-        banner = (TileEntityBanner) world.getTileEntityAt(getX(), getY(), getZ());
-
-        base = DyeColor.getByDyeData((byte) banner.color.getInvColorIndex());
-
-        if (banner.patterns != null) {
-            for (int i = 0; i < banner.patterns.size(); i++) {
-                NBTTagCompound p = (NBTTagCompound) banner.patterns.get(i);
-                patterns.add(new Pattern(DyeColor.getByDyeData((byte) p.getInt("Color")), PatternType.getByIdentifier(p.getString("Pattern"))));
-            }
-        }
+        super(block, TileEntityBanner.class);
     }
 
     public CraftBanner(final Material material, final TileEntityBanner te) {
-        super(material);
-        banner = te;
+        super(material, te);
+    }
+
+    @Override
+    public void load(TileEntityBanner banner) {
+        super.load(banner);
 
         base = DyeColor.getByDyeData((byte) banner.color.getInvColorIndex());
 
@@ -96,31 +86,19 @@ public class CraftBanner extends CraftBlockState implements Banner {
     }
 
     @Override
-    public boolean update(boolean force, boolean applyPhysics) {
-        boolean result = super.update(force, applyPhysics);
+    public void applyTo(TileEntityBanner banner) {
+        super.applyTo(banner);
 
-        if (result) {
-            banner.color = EnumColor.fromInvColorIndex(base.getDyeData());
+        banner.color = EnumColor.fromInvColorIndex(base.getDyeData());
 
-            NBTTagList newPatterns = new NBTTagList();
+        NBTTagList newPatterns = new NBTTagList();
 
-            for (Pattern p : patterns) {
-                NBTTagCompound compound = new NBTTagCompound();
-                compound.setInt("Color", p.getColor().getDyeData());
-                compound.setString("Pattern", p.getPattern().getIdentifier());
-                newPatterns.add(compound);
-            }
-
-            banner.patterns = newPatterns;
-
-            banner.update();
+        for (Pattern p : patterns) {
+            NBTTagCompound compound = new NBTTagCompound();
+            compound.setInt("Color", p.getColor().getDyeData());
+            compound.setString("Pattern", p.getPattern().getIdentifier());
+            newPatterns.add(compound);
         }
-
-        return result;
-    }
-
-    @Override
-    public TileEntityBanner getTileEntity() {
-        return banner;
+        banner.patterns = newPatterns;
     }
 }
diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftBeacon.java b/src/main/java/org/bukkit/craftbukkit/block/CraftBeacon.java
index a679221a41..afec900c67 100644
--- a/src/main/java/org/bukkit/craftbukkit/block/CraftBeacon.java
+++ b/src/main/java/org/bukkit/craftbukkit/block/CraftBeacon.java
@@ -4,98 +4,94 @@ import java.util.ArrayList;
 import java.util.Collection;
 import net.minecraft.server.EntityHuman;
 import net.minecraft.server.MobEffectList;
+import net.minecraft.server.TileEntity;
 import net.minecraft.server.TileEntityBeacon;
 import org.bukkit.Material;
 import org.bukkit.block.Beacon;
 import org.bukkit.block.Block;
-import org.bukkit.craftbukkit.CraftWorld;
 import org.bukkit.craftbukkit.inventory.CraftInventoryBeacon;
 import org.bukkit.entity.LivingEntity;
-import org.bukkit.inventory.Inventory;
+import org.bukkit.inventory.BeaconInventory;
 import org.bukkit.potion.PotionEffect;
 import org.bukkit.potion.PotionEffectType;
 
-public class CraftBeacon extends CraftContainer implements Beacon {
-    private final CraftWorld world;
-    private final TileEntityBeacon beacon;
+public class CraftBeacon extends CraftContainer<TileEntityBeacon> implements Beacon {
 
     public CraftBeacon(final Block block) {
-        super(block);
-
-        world = (CraftWorld) block.getWorld();
-        beacon = (TileEntityBeacon) world.getTileEntityAt(getX(), getY(), getZ());
+        super(block, TileEntityBeacon.class);
     }
 
     public CraftBeacon(final Material material, final TileEntityBeacon te) {
         super(material, te);
-        world = null;
-        beacon = te;
-    }
-
-    public Inventory getInventory() {
-        return new CraftInventoryBeacon(beacon);
     }
 
     @Override
-    public boolean update(boolean force, boolean applyPhysics) {
-        boolean result = super.update(force, applyPhysics);
+    public BeaconInventory getSnapshotInventory() {
+        return new CraftInventoryBeacon(this.getSnapshot());
+    }
 
-        if (result) {
-            beacon.update();
+    @Override
+    public BeaconInventory getInventory() {
+        if (!this.isPlaced()) {
+            return this.getSnapshotInventory();
         }
 
-        return result;
-    }
-
-    @Override
-    public TileEntityBeacon getTileEntity() {
-        return beacon;
+        return new CraftInventoryBeacon(this.getTileEntity());
     }
 
     @Override
     public Collection<LivingEntity> getEntitiesInRange() {
-        Collection<EntityHuman> nms = beacon.getHumansInRange();
-        Collection<LivingEntity> bukkit = new ArrayList<LivingEntity>(nms.size());
+        TileEntity tileEntity = this.getTileEntityFromWorld();
+        if (tileEntity instanceof TileEntityBeacon) {
+            TileEntityBeacon beacon = (TileEntityBeacon) tileEntity;
 
-        for (EntityHuman human : nms) {
-            bukkit.add(human.getBukkitEntity());
+            Collection<EntityHuman> nms = beacon.getHumansInRange();
+            Collection<LivingEntity> bukkit = new ArrayList<LivingEntity>(nms.size());
+
+            for (EntityHuman human : nms) {
+                bukkit.add(human.getBukkitEntity());
+            }
+
+            return bukkit;
         }
 
-        return bukkit;
+        // block is no longer a beacon
+        return new ArrayList<LivingEntity>();
     }
 
     @Override
     public int getTier() {
-        return beacon.levels;
+        return this.getSnapshot().levels;
     }
 
     @Override
     public PotionEffect getPrimaryEffect() {
-        return beacon.getPrimaryEffect();
+        return this.getSnapshot().getPrimaryEffect();
     }
 
     @Override
     public void setPrimaryEffect(PotionEffectType effect) {
-        beacon.primaryEffect = (effect != null) ? MobEffectList.fromId(effect.getId()) : null;
+        this.getSnapshot().primaryEffect = (effect != null) ? MobEffectList.fromId(effect.getId()) : null;
     }
 
     @Override
     public PotionEffect getSecondaryEffect() {
-        return beacon.getSecondaryEffect();
+        return this.getSnapshot().getSecondaryEffect();
     }
 
     @Override
     public void setSecondaryEffect(PotionEffectType effect) {
-        beacon.secondaryEffect = (effect != null) ? MobEffectList.fromId(effect.getId()) : null;
+        this.getSnapshot().secondaryEffect = (effect != null) ? MobEffectList.fromId(effect.getId()) : null;
     }
 
     @Override
     public String getCustomName() {
+        TileEntityBeacon beacon = this.getSnapshot();
         return beacon.hasCustomName() ? beacon.getName() : null;
     }
 
     @Override
     public void setCustomName(String name) {
-        beacon.setCustomName(name);
+        this.getSnapshot().setCustomName(name);
     }
 }
diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftBed.java b/src/main/java/org/bukkit/craftbukkit/block/CraftBed.java
index f6083565bd..27756d8587 100644
--- a/src/main/java/org/bukkit/craftbukkit/block/CraftBed.java
+++ b/src/main/java/org/bukkit/craftbukkit/block/CraftBed.java
@@ -2,36 +2,29 @@ package org.bukkit.craftbukkit.block;
 
 import com.google.common.base.Preconditions;
 import net.minecraft.server.EnumColor;
-import net.minecraft.server.TileEntity;
 import net.minecraft.server.TileEntityBed;
 import org.bukkit.DyeColor;
 import org.bukkit.Material;
 import org.bukkit.block.Bed;
 import org.bukkit.block.Block;
-import org.bukkit.craftbukkit.CraftWorld;
 
-public class CraftBed extends CraftBlockState implements Bed {
+public class CraftBed extends CraftBlockEntityState<TileEntityBed> implements Bed {
 
-    private final TileEntityBed bed;
     private DyeColor color;
 
     public CraftBed(Block block) {
-        super(block);
-
-        bed = (TileEntityBed) ((CraftWorld) block.getWorld()).getTileEntityAt(getX(), getY(), getZ());
-        color = DyeColor.getByWoolData((byte) bed.a().getColorIndex());
+        super(block, TileEntityBed.class);
     }
 
     public CraftBed(Material material, TileEntityBed te) {
-        super(material);
-
-        bed = te;
-        color = DyeColor.getByWoolData((byte) bed.a().getColorIndex());
+        super(material, te);
     }
 
     @Override
-    public TileEntity getTileEntity() {
-        return bed;
+    public void load(TileEntityBed bed) {
+        super.load(bed);
+
+        color = DyeColor.getByWoolData((byte) bed.a().getColorIndex());
     }
 
     @Override
@@ -47,14 +40,9 @@ public class CraftBed extends CraftBlockState implements Bed {
     }
 
     @Override
-    public boolean update(boolean force, boolean applyPhysics) {
-        boolean result = super.update(force, applyPhysics);
+    public void applyTo(TileEntityBed bed) {
+        super.applyTo(bed);
 
-        if (result) {
-            bed.a(EnumColor.fromColorIndex(color.getWoolData()));
-            bed.update();
-        }
-
-        return result;
+        bed.a(EnumColor.fromColorIndex(color.getWoolData()));
     }
 }
diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java b/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java
index a2d633797e..ba1cdc18fe 100644
--- a/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java
+++ b/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java
@@ -336,7 +336,14 @@ public class CraftBlock implements Block {
         case BED_BLOCK:
             return new CraftBed(this);
         default:
-            return new CraftBlockState(this);
+            TileEntity tileEntity = chunk.getCraftWorld().getTileEntityAt(x, y, z);
+            if (tileEntity != null) {
+                // block with unhandled TileEntity:
+                return new CraftBlockEntityState<TileEntity>(this, (Class<TileEntity>) tileEntity.getClass());
+            } else {
+                // Block without TileEntity:
+                return new CraftBlockState(this);
+            }
         }
     }
 
diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftBlockEntityState.java b/src/main/java/org/bukkit/craftbukkit/block/CraftBlockEntityState.java
new file mode 100644
index 0000000000..cf94c06269
--- /dev/null
+++ b/src/main/java/org/bukkit/craftbukkit/block/CraftBlockEntityState.java
@@ -0,0 +1,120 @@
+package org.bukkit.craftbukkit.block;
+
+import net.minecraft.server.BlockPosition;
+import net.minecraft.server.NBTTagCompound;
+import net.minecraft.server.TileEntity;
+import org.bukkit.Material;
+import org.bukkit.block.Block;
+import org.bukkit.craftbukkit.CraftWorld;
+
+public class CraftBlockEntityState<T extends TileEntity> extends CraftBlockState {
+
+    private final Class<T> tileEntityClass;
+    private final T tileEntity;
+    private final T snapshot;
+
+    public CraftBlockEntityState(Block block, Class<T> tileEntityClass) {
+        super(block);
+
+        this.tileEntityClass = tileEntityClass;
+
+        // get tile entity from block:
+        CraftWorld world = (CraftWorld) this.getWorld();
+        this.tileEntity = tileEntityClass.cast(world.getTileEntityAt(this.getX(), this.getY(), this.getZ()));
+
+        // copy tile entity data:
+        this.snapshot = this.createSnapshot(tileEntity);
+        this.load(snapshot);
+    }
+
+    public CraftBlockEntityState(Material material, T tileEntity) {
+        super(material);
+
+        this.tileEntityClass = (Class<T>) tileEntity.getClass();
+        this.tileEntity = tileEntity;
+
+        // copy tile entity data:
+        this.snapshot = this.createSnapshot(tileEntity);
+        this.load(snapshot);
+    }
+
+    private T createSnapshot(T tileEntity) {
+        if (tileEntity == null) {
+            return null;
+        }
+
+        NBTTagCompound nbtTagCompound = tileEntity.save(new NBTTagCompound());
+        T snapshot = (T) TileEntity.create(null, nbtTagCompound);
+
+        return snapshot;
+    }
+
+    // copies the TileEntity-specific data, retains the position
+    private void copyData(T from, T to) {
+        BlockPosition pos = to.getPosition();
+        NBTTagCompound nbtTagCompound = from.save(new NBTTagCompound());
+        to.load(nbtTagCompound);
+
+        // reset the original position:
+        to.setPosition(pos);
+    }
+
+    // gets the wrapped TileEntity
+    protected T getTileEntity() {
+        return tileEntity;
+    }
+
+    // gets the cloned TileEntity which is used to store the captured data
+    protected T getSnapshot() {
+        return snapshot;
+    }
+
+    // gets the current TileEntity from the world at this position
+    protected TileEntity getTileEntityFromWorld() {
+        requirePlaced();
+
+        return ((CraftWorld) this.getWorld()).getTileEntityAt(this.getX(), this.getY(), this.getZ());
+    }
+
+    // gets the NBT data of the TileEntity represented by this block state
+    public NBTTagCompound getSnapshotNBT() {
+        // update snapshot
+        applyTo(snapshot);
+
+        return snapshot.save(new NBTTagCompound());
+    }
+
+    // copies the data of the given tile entity data to this block state
+    protected void load(T tileEntity) {
+        if (tileEntity != null && tileEntity != snapshot) {
+            copyData(tileEntity, snapshot);
+        }
+    }
+
+    // applies the TileEntity data of this block state to the given TileEntity
+    protected void applyTo(T tileEntity) {
+        if (tileEntity != null && tileEntity != snapshot) {
+            copyData(snapshot, tileEntity);
+        }
+    }
+
+    protected boolean isApplicable(TileEntity tileEntity) {
+        return tileEntityClass.isInstance(tileEntity);
+    }
+
+    @Override
+    public boolean update(boolean force, boolean applyPhysics) {
+        boolean result = super.update(force, applyPhysics);
+
+        if (result && this.isPlaced()) {
+            TileEntity tile = getTileEntityFromWorld();
+
+            if (isApplicable(tile)) {
+                applyTo(tileEntityClass.cast(tile));
+                tile.update();
+            }
+        }
+
+        return result;
+    }
+}
diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftBlockState.java b/src/main/java/org/bukkit/craftbukkit/block/CraftBlockState.java
index 5d83155a12..2a1b731c0c 100644
--- a/src/main/java/org/bukkit/craftbukkit/block/CraftBlockState.java
+++ b/src/main/java/org/bukkit/craftbukkit/block/CraftBlockState.java
@@ -3,7 +3,6 @@ package org.bukkit.craftbukkit.block;
 import net.minecraft.server.BlockPosition;
 import org.bukkit.Location;
 import org.bukkit.block.Block;
-import org.bukkit.block.BlockFace;
 import org.bukkit.Chunk;
 import org.bukkit.Material;
 import org.bukkit.World;
@@ -17,9 +16,7 @@ import org.bukkit.metadata.MetadataValue;
 import org.bukkit.plugin.Plugin;
 
 import java.util.List;
-import net.minecraft.server.EnumDirection;
 import net.minecraft.server.IBlockData;
-import net.minecraft.server.TileEntity;
 
 public class CraftBlockState implements BlockState {
     private final CraftWorld world;
@@ -256,10 +253,6 @@ public class CraftBlockState implements BlockState {
         return hash;
     }
 
-    public TileEntity getTileEntity() {
-        return null;
-    }
-
     public void setMetadata(String metadataKey, MetadataValue newMetadataValue) {
         requirePlaced();
         chunk.getCraftWorld().getBlockMetadata().setMetadata(getBlock(), metadataKey, newMetadataValue);
diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftBrewingStand.java b/src/main/java/org/bukkit/craftbukkit/block/CraftBrewingStand.java
index 78e8c9c605..4f717f2849 100644
--- a/src/main/java/org/bukkit/craftbukkit/block/CraftBrewingStand.java
+++ b/src/main/java/org/bukkit/craftbukkit/block/CraftBrewingStand.java
@@ -4,69 +4,61 @@ import net.minecraft.server.TileEntityBrewingStand;
 import org.bukkit.Material;
 import org.bukkit.block.Block;
 import org.bukkit.block.BrewingStand;
-import org.bukkit.craftbukkit.CraftWorld;
 import org.bukkit.craftbukkit.inventory.CraftInventoryBrewer;
 import org.bukkit.inventory.BrewerInventory;
 
-public class CraftBrewingStand extends CraftContainer implements BrewingStand {
-    private final TileEntityBrewingStand brewingStand;
+public class CraftBrewingStand extends CraftContainer<TileEntityBrewingStand> implements BrewingStand {
 
     public CraftBrewingStand(Block block) {
-        super(block);
-
-        brewingStand = (TileEntityBrewingStand) ((CraftWorld) block.getWorld()).getTileEntityAt(getX(), getY(), getZ());
+        super(block, TileEntityBrewingStand.class);
     }
 
     public CraftBrewingStand(final Material material, final TileEntityBrewingStand te) {
         super(material, te);
-        brewingStand = te;
-    }
-
-    public BrewerInventory getInventory() {
-        return new CraftInventoryBrewer(brewingStand);
     }
 
     @Override
-    public boolean update(boolean force, boolean applyPhysics) {
-        boolean result = super.update(force, applyPhysics);
+    public BrewerInventory getSnapshotInventory() {
+        return new CraftInventoryBrewer(this.getSnapshot());
+    }
 
-        if (result) {
-            brewingStand.update();
+    @Override
+    public BrewerInventory getInventory() {
+        if (!this.isPlaced()) {
+            return this.getSnapshotInventory();
         }
 
-        return result;
-    }
-
-    public int getBrewingTime() {
-        return brewingStand.getProperty(0);
-    }
-
-    public void setBrewingTime(int brewTime) {
-        brewingStand.setProperty(0, brewTime);
+        return new CraftInventoryBrewer(this.getTileEntity());
     }
 
     @Override
-    public TileEntityBrewingStand getTileEntity() {
-        return brewingStand;
+    public int getBrewingTime() {
+        return this.getSnapshot().getProperty(0);
+    }
+
+    @Override
+    public void setBrewingTime(int brewTime) {
+        this.getSnapshot().setProperty(0, brewTime);
     }
 
     @Override
     public int getFuelLevel() {
-        return brewingStand.getProperty(1);
+        return this.getSnapshot().getProperty(1);
     }
 
     @Override
     public void setFuelLevel(int level) {
-        brewingStand.setProperty(1, level);
+        this.getSnapshot().setProperty(1, level);
     }
 
     @Override
     public String getCustomName() {
+        TileEntityBrewingStand brewingStand = this.getSnapshot();
         return brewingStand.hasCustomName() ? brewingStand.getName() : null;
     }
 
     @Override
     public void setCustomName(String name) {
-        brewingStand.setCustomName(name);
+        this.getSnapshot().setCustomName(name);
     }
 }
diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftChest.java b/src/main/java/org/bukkit/craftbukkit/block/CraftChest.java
index 3de7e14d80..85f3bb2720 100644
--- a/src/main/java/org/bukkit/craftbukkit/block/CraftChest.java
+++ b/src/main/java/org/bukkit/craftbukkit/block/CraftChest.java
@@ -11,36 +11,43 @@ import org.bukkit.craftbukkit.inventory.CraftInventory;
 import org.bukkit.craftbukkit.inventory.CraftInventoryDoubleChest;
 import org.bukkit.inventory.Inventory;
 
-public class CraftChest extends CraftLootable implements Chest {
-    private final CraftWorld world;
-    private final TileEntityChest chest;
+public class CraftChest extends CraftLootable<TileEntityChest> implements Chest {
 
     public CraftChest(final Block block) {
-        super(block);
-
-        world = (CraftWorld) block.getWorld();
-        chest = (TileEntityChest) world.getTileEntityAt(getX(), getY(), getZ());
+        super(block, TileEntityChest.class);
     }
 
     public CraftChest(final Material material, final TileEntityChest te) {
         super(material, te);
-        chest = te;
-        world = null;
     }
 
+    @Override
+    public Inventory getSnapshotInventory() {
+        return new CraftInventory(this.getSnapshot());
+    }
+
+    @Override
     public Inventory getBlockInventory() {
-        return new CraftInventory(chest);
+        if (!this.isPlaced()) {
+            return this.getSnapshotInventory();
+        }
+
+        return new CraftInventory(this.getTileEntity());
     }
 
+    @Override
     public Inventory getInventory() {
-        int x = getX();
-        int y = getY();
-        int z = getZ();
-        // The logic here is basically identical to the logic in BlockChest.interact
-        CraftInventory inventory = new CraftInventory(chest);
+        CraftInventory inventory = (CraftInventory) this.getBlockInventory();
         if (!isPlaced()) {
             return inventory;
         }
+
+        // The logic here is basically identical to the logic in BlockChest.interact
+        int x = this.getX();
+        int y = this.getY();
+        int z = this.getZ();
+        CraftWorld world = (CraftWorld) this.getWorld();
+
         int id;
         if (world.getBlockTypeIdAt(x, y, z) == Material.CHEST.getId()) {
             id = Material.CHEST.getId();
@@ -51,7 +58,7 @@ public class CraftChest extends CraftLootable implements Chest {
         }
 
         if (world.getBlockTypeIdAt(x - 1, y, z) == id) {
-            CraftInventory left = new CraftInventory((TileEntityChest)world.getHandle().getTileEntity(new BlockPosition(x - 1, y, z)));
+            CraftInventory left = new CraftInventory((TileEntityChest) world.getHandle().getTileEntity(new BlockPosition(x - 1, y, z)));
             inventory = new CraftInventoryDoubleChest(left, inventory);
         }
         if (world.getBlockTypeIdAt(x + 1, y, z) == id) {
@@ -68,20 +75,4 @@ public class CraftChest extends CraftLootable implements Chest {
         }
         return inventory;
     }
-
-    @Override
-    public boolean update(boolean force, boolean applyPhysics) {
-        boolean result = super.update(force, applyPhysics);
-
-        if (result) {
-            chest.update();
-        }
-
-        return result;
-    }
-
-    @Override
-    public TileEntityChest getTileEntity() {
-        return chest;
-    }
 }
diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftCommandBlock.java b/src/main/java/org/bukkit/craftbukkit/block/CraftCommandBlock.java
index 9bbc790509..dd5b83cf55 100644
--- a/src/main/java/org/bukkit/craftbukkit/block/CraftCommandBlock.java
+++ b/src/main/java/org/bukkit/craftbukkit/block/CraftCommandBlock.java
@@ -4,58 +4,53 @@ import net.minecraft.server.TileEntityCommand;
 import org.bukkit.Material;
 import org.bukkit.block.Block;
 import org.bukkit.block.CommandBlock;
-import org.bukkit.craftbukkit.CraftWorld;
 
-public class CraftCommandBlock extends CraftBlockState implements CommandBlock {
-    private final TileEntityCommand commandBlock;
+public class CraftCommandBlock extends CraftBlockEntityState<TileEntityCommand> implements CommandBlock {
+
     private String command;
     private String name;
 
     public CraftCommandBlock(Block block) {
-        super(block);
-
-        CraftWorld world = (CraftWorld) block.getWorld();
-        commandBlock = (TileEntityCommand) world.getTileEntityAt(getX(), getY(), getZ());
-        command = commandBlock.getCommandBlock().getCommand();
-        name = commandBlock.getCommandBlock().getName();
+        super(block, TileEntityCommand.class);
     }
 
     public CraftCommandBlock(final Material material, final TileEntityCommand te) {
-        super(material);
-        commandBlock = te;
+        super(material, te);
+    }
+
+    @Override
+    public void load(TileEntityCommand commandBlock) {
+        super.load(commandBlock);
+
         command = commandBlock.getCommandBlock().getCommand();
         name = commandBlock.getCommandBlock().getName();
     }
 
+    @Override
     public String getCommand() {
         return command;
     }
 
+    @Override
     public void setCommand(String command) {
         this.command = command != null ? command : "";
     }
 
+    @Override
     public String getName() {
         return name;
     }
 
+    @Override
     public void setName(String name) {
         this.name = name != null ? name : "@";
     }
 
-    public boolean update(boolean force, boolean applyPhysics) {
-        boolean result = super.update(force, applyPhysics);
-
-        if (result) {
-            commandBlock.getCommandBlock().setCommand(command);
-            commandBlock.getCommandBlock().setName(name);
-        }
-
-        return result;
-    }
-
     @Override
-    public TileEntityCommand getTileEntity() {
-        return commandBlock;
+    public void applyTo(TileEntityCommand commandBlock) {
+        super.applyTo(commandBlock);
+
+        commandBlock.getCommandBlock().setCommand(command);
+        commandBlock.getCommandBlock().setName(name);
     }
 }
diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftComparator.java b/src/main/java/org/bukkit/craftbukkit/block/CraftComparator.java
index d39e2fcc7f..2e6a738ac7 100644
--- a/src/main/java/org/bukkit/craftbukkit/block/CraftComparator.java
+++ b/src/main/java/org/bukkit/craftbukkit/block/CraftComparator.java
@@ -1,33 +1,17 @@
 package org.bukkit.craftbukkit.block;
 
-import net.minecraft.server.TileEntity;
 import net.minecraft.server.TileEntityComparator;
 import org.bukkit.Material;
 import org.bukkit.block.Block;
 import org.bukkit.block.Comparator;
-import org.bukkit.craftbukkit.CraftWorld;
 
-public class CraftComparator extends CraftBlockState implements Comparator {
-
-    private final CraftWorld world;
-    private final TileEntityComparator comparator;
+public class CraftComparator extends CraftBlockEntityState<TileEntityComparator> implements Comparator {
 
     public CraftComparator(final Block block) {
-        super(block);
-
-        world = (CraftWorld) block.getWorld();
-        comparator = (TileEntityComparator) world.getTileEntityAt(getX(), getY(), getZ());
+        super(block, TileEntityComparator.class);
     }
 
     public CraftComparator(final Material material, final TileEntityComparator te) {
-        super(material);
-
-        comparator = te;
-        world = null;
-    }
-
-    @Override
-    public TileEntity getTileEntity() {
-        return comparator;
+        super(material, te);
     }
 }
diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftContainer.java b/src/main/java/org/bukkit/craftbukkit/block/CraftContainer.java
index 6aad6663db..06a1d4473a 100644
--- a/src/main/java/org/bukkit/craftbukkit/block/CraftContainer.java
+++ b/src/main/java/org/bukkit/craftbukkit/block/CraftContainer.java
@@ -1,41 +1,33 @@
 package org.bukkit.craftbukkit.block;
 
 import net.minecraft.server.ChestLock;
-import net.minecraft.server.ITileInventory;
 import net.minecraft.server.TileEntityContainer;
 import org.bukkit.Material;
 import org.bukkit.block.Block;
-import org.bukkit.block.Lockable;
-import org.bukkit.craftbukkit.CraftWorld;
+import org.bukkit.block.Container;
 
-public class CraftContainer extends CraftBlockState implements Lockable {
+public abstract class CraftContainer<T extends TileEntityContainer> extends CraftBlockEntityState<T> implements Container {
 
-    private final ITileInventory container;
-
-    public CraftContainer(Block block) {
-        super(block);
-
-        container = (TileEntityContainer) ((CraftWorld) block.getWorld()).getTileEntityAt(block.getX(), block.getY(), block.getZ());
+    public CraftContainer(Block block, Class<T> tileEntityClass) {
+        super(block, tileEntityClass);
     }
 
-    public CraftContainer(final Material material, ITileInventory tileEntity) {
-        super(material);
-
-        container = tileEntity;
+    public CraftContainer(final Material material, T tileEntity) {
+        super(material, tileEntity);
     }
 
     @Override
     public boolean isLocked() {
-        return container.isLocked();
+        return this.getSnapshot().isLocked();
     }
 
     @Override
     public String getLock() {
-        return container.getLock().getKey();
+        return this.getSnapshot().getLock().getKey();
     }
 
     @Override
     public void setLock(String key) {
-        container.setLock(key == null ? ChestLock.a : new ChestLock(key));
+        this.getSnapshot().setLock(key == null ? ChestLock.a : new ChestLock(key));
     }
 }
diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftCreatureSpawner.java b/src/main/java/org/bukkit/craftbukkit/block/CraftCreatureSpawner.java
index 1596b9cc39..67f4c73036 100644
--- a/src/main/java/org/bukkit/craftbukkit/block/CraftCreatureSpawner.java
+++ b/src/main/java/org/bukkit/craftbukkit/block/CraftCreatureSpawner.java
@@ -6,40 +6,39 @@ import org.bukkit.Material;
 
 import org.bukkit.block.Block;
 import org.bukkit.block.CreatureSpawner;
-import org.bukkit.craftbukkit.CraftWorld;
 import org.bukkit.entity.EntityType;
 
-public class CraftCreatureSpawner extends CraftBlockState implements CreatureSpawner {
-    private final TileEntityMobSpawner spawner;
+public class CraftCreatureSpawner extends CraftBlockEntityState<TileEntityMobSpawner> implements CreatureSpawner {
 
     public CraftCreatureSpawner(final Block block) {
-        super(block);
-
-        spawner = (TileEntityMobSpawner) ((CraftWorld) block.getWorld()).getTileEntityAt(getX(), getY(), getZ());
+        super(block, TileEntityMobSpawner.class);
     }
 
     public CraftCreatureSpawner(final Material material, TileEntityMobSpawner te) {
-        super(material);
-        spawner = te;
+        super(material, te);
     }
 
+    @Override
     public EntityType getSpawnedType() {
-        MinecraftKey key = spawner.getSpawner().getMobName();
+        MinecraftKey key = this.getSnapshot().getSpawner().getMobName();
         return (key == null) ? EntityType.PIG : EntityType.fromName(key.getKey());
     }
 
+    @Override
     public void setSpawnedType(EntityType entityType) {
         if (entityType == null || entityType.getName() == null) {
             throw new IllegalArgumentException("Can't spawn EntityType " + entityType + " from mobspawners!");
         }
 
-        spawner.getSpawner().setMobName(new MinecraftKey(entityType.getName()));
+        this.getSnapshot().getSpawner().setMobName(new MinecraftKey(entityType.getName()));
     }
 
+    @Override
     public String getCreatureTypeName() {
-        return spawner.getSpawner().getMobName().getKey();
+        return this.getSnapshot().getSpawner().getMobName().getKey();
     }
 
+    @Override
     public void setCreatureTypeByName(String creatureType) {
         // Verify input
         EntityType type = EntityType.fromName(creatureType);
@@ -49,16 +48,13 @@ public class CraftCreatureSpawner extends CraftBlockState implements CreatureSpa
         setSpawnedType(type);
     }
 
+    @Override
     public int getDelay() {
-        return spawner.getSpawner().spawnDelay;
-    }
-
-    public void setDelay(int delay) {
-        spawner.getSpawner().spawnDelay = delay;
+        return this.getSnapshot().getSpawner().spawnDelay;
     }
 
     @Override
-    public TileEntityMobSpawner getTileEntity() {
-        return spawner;
+    public void setDelay(int delay) {
+        this.getSnapshot().getSpawner().spawnDelay = delay;
     }
 }
diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftDaylightDetector.java b/src/main/java/org/bukkit/craftbukkit/block/CraftDaylightDetector.java
index 039df2fd9c..1c9b84c69c 100644
--- a/src/main/java/org/bukkit/craftbukkit/block/CraftDaylightDetector.java
+++ b/src/main/java/org/bukkit/craftbukkit/block/CraftDaylightDetector.java
@@ -1,33 +1,17 @@
 package org.bukkit.craftbukkit.block;
 
-import net.minecraft.server.TileEntity;
 import net.minecraft.server.TileEntityLightDetector;
 import org.bukkit.Material;
 import org.bukkit.block.Block;
 import org.bukkit.block.DaylightDetector;
-import org.bukkit.craftbukkit.CraftWorld;
 
-public class CraftDaylightDetector extends CraftBlockState implements DaylightDetector {
-
-    private final CraftWorld world;
-    private final TileEntityLightDetector detector;
+public class CraftDaylightDetector extends CraftBlockEntityState<TileEntityLightDetector> implements DaylightDetector {
 
     public CraftDaylightDetector(final Block block) {
-        super(block);
-
-        world = (CraftWorld) block.getWorld();
-        detector = (TileEntityLightDetector) world.getTileEntityAt(getX(), getY(), getZ());
+        super(block, TileEntityLightDetector.class);
     }
 
     public CraftDaylightDetector(final Material material, final TileEntityLightDetector te) {
-        super(material);
-
-        detector = te;
-        world = null;
-    }
-
-    @Override
-    public TileEntity getTileEntity() {
-        return detector;
+        super(material, te);
     }
 }
diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftDispenser.java b/src/main/java/org/bukkit/craftbukkit/block/CraftDispenser.java
index cc0d28f217..1dc8bfecd2 100644
--- a/src/main/java/org/bukkit/craftbukkit/block/CraftDispenser.java
+++ b/src/main/java/org/bukkit/craftbukkit/block/CraftDispenser.java
@@ -14,27 +14,31 @@ import org.bukkit.craftbukkit.projectiles.CraftBlockProjectileSource;
 import org.bukkit.inventory.Inventory;
 import org.bukkit.projectiles.BlockProjectileSource;
 
-public class CraftDispenser extends CraftLootable implements Dispenser {
-    private final CraftWorld world;
-    private final TileEntityDispenser dispenser;
+public class CraftDispenser extends CraftLootable<TileEntityDispenser> implements Dispenser {
 
     public CraftDispenser(final Block block) {
-        super(block);
-
-        world = (CraftWorld) block.getWorld();
-        dispenser = (TileEntityDispenser) world.getTileEntityAt(getX(), getY(), getZ());
+        super(block, TileEntityDispenser.class);
     }
 
     public CraftDispenser(final Material material, final TileEntityDispenser te) {
         super(material, te);
-        world = null;
-        dispenser = te;
     }
 
+    @Override
+    public Inventory getSnapshotInventory() {
+        return new CraftInventory(this.getSnapshot());
+    }
+
+    @Override
     public Inventory getInventory() {
-        return new CraftInventory(dispenser);
+        if (!this.isPlaced()) {
+            return this.getSnapshotInventory();
+        }
+
+        return new CraftInventory(this.getTileEntity());
     }
 
+    @Override
     public BlockProjectileSource getBlockProjectileSource() {
         Block block = getBlock();
 
@@ -42,13 +46,15 @@ public class CraftDispenser extends CraftLootable implements Dispenser {
             return null;
         }
 
-        return new CraftBlockProjectileSource(dispenser);
+        return new CraftBlockProjectileSource((TileEntityDispenser) this.getTileEntityFromWorld());
     }
 
+    @Override
     public boolean dispense() {
         Block block = getBlock();
 
         if (block.getType() == Material.DISPENSER) {
+            CraftWorld world = (CraftWorld) this.getWorld();
             BlockDispenser dispense = (BlockDispenser) Blocks.DISPENSER;
 
             dispense.dispense(world.getHandle(), new BlockPosition(getX(), getY(), getZ()));
@@ -57,20 +63,4 @@ public class CraftDispenser extends CraftLootable implements Dispenser {
             return false;
         }
     }
-
-    @Override
-    public boolean update(boolean force, boolean applyPhysics) {
-        boolean result = super.update(force, applyPhysics);
-
-        if (result) {
-            dispenser.update();
-        }
-
-        return result;
-    }
-
-    @Override
-    public TileEntityDispenser getTileEntity() {
-        return dispenser;
-    }
 }
diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftDropper.java b/src/main/java/org/bukkit/craftbukkit/block/CraftDropper.java
index 8786d049e7..27f6e66ec8 100644
--- a/src/main/java/org/bukkit/craftbukkit/block/CraftDropper.java
+++ b/src/main/java/org/bukkit/craftbukkit/block/CraftDropper.java
@@ -12,50 +12,39 @@ import org.bukkit.craftbukkit.CraftWorld;
 import org.bukkit.craftbukkit.inventory.CraftInventory;
 import org.bukkit.inventory.Inventory;
 
-public class CraftDropper extends CraftLootable implements Dropper {
-    private final CraftWorld world;
-    private final TileEntityDropper dropper;
+public class CraftDropper extends CraftLootable<TileEntityDropper> implements Dropper {
 
     public CraftDropper(final Block block) {
-        super(block);
-
-        world = (CraftWorld) block.getWorld();
-        dropper = (TileEntityDropper) world.getTileEntityAt(getX(), getY(), getZ());
+        super(block, TileEntityDropper.class);
     }
 
     public CraftDropper(final Material material, TileEntityDropper te) {
         super(material, te);
-        world = null;
-        dropper = te;
     }
 
+    @Override
+    public Inventory getSnapshotInventory() {
+        return new CraftInventory(this.getSnapshot());
+    }
+
+    @Override
     public Inventory getInventory() {
-        return new CraftInventory(dropper);
+        if (!this.isPlaced()) {
+            return this.getSnapshotInventory();
+        }
+
+        return new CraftInventory(this.getTileEntity());
     }
 
+    @Override
     public void drop() {
         Block block = getBlock();
 
         if (block.getType() == Material.DROPPER) {
+            CraftWorld world = (CraftWorld) this.getWorld();
             BlockDropper drop = (BlockDropper) Blocks.DROPPER;
 
             drop.dispense(world.getHandle(), new BlockPosition(getX(), getY(), getZ()));
         }
     }
-
-    @Override
-    public boolean update(boolean force, boolean applyPhysics) {
-        boolean result = super.update(force, applyPhysics);
-
-        if (result) {
-            dropper.update();
-        }
-
-        return result;
-    }
-
-    @Override
-    public TileEntityDropper getTileEntity() {
-        return dropper;
-    }
 }
diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftEnchantingTable.java b/src/main/java/org/bukkit/craftbukkit/block/CraftEnchantingTable.java
index e20bb4983f..c5a1326d45 100644
--- a/src/main/java/org/bukkit/craftbukkit/block/CraftEnchantingTable.java
+++ b/src/main/java/org/bukkit/craftbukkit/block/CraftEnchantingTable.java
@@ -1,43 +1,28 @@
 package org.bukkit.craftbukkit.block;
 
-import net.minecraft.server.TileEntity;
 import net.minecraft.server.TileEntityEnchantTable;
 import org.bukkit.Material;
 import org.bukkit.block.Block;
-import org.bukkit.craftbukkit.CraftWorld;
 import org.bukkit.block.EnchantingTable;
 
-public class CraftEnchantingTable extends CraftBlockState implements EnchantingTable {
-
-    private final CraftWorld world;
-    private final TileEntityEnchantTable enchant;
+public class CraftEnchantingTable extends CraftBlockEntityState<TileEntityEnchantTable> implements EnchantingTable {
 
     public CraftEnchantingTable(final Block block) {
-        super(block);
-
-        world = (CraftWorld) block.getWorld();
-        enchant = (TileEntityEnchantTable) world.getTileEntityAt(getX(), getY(), getZ());
+        super(block, TileEntityEnchantTable.class);
     }
 
     public CraftEnchantingTable(final Material material, final TileEntityEnchantTable te) {
-        super(material);
-
-        enchant = te;
-        world = null;
-    }
-
-    @Override
-    public TileEntity getTileEntity() {
-        return enchant;
+        super(material, te);
     }
 
     @Override
     public String getCustomName() {
+        TileEntityEnchantTable enchant = this.getSnapshot();
         return enchant.hasCustomName() ? enchant.getName() : null;
     }
 
     @Override
     public void setCustomName(String name) {
-        enchant.setCustomName(name);
+        this.getSnapshot().setCustomName(name);
     }
 }
diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftEndGateway.java b/src/main/java/org/bukkit/craftbukkit/block/CraftEndGateway.java
index 45f222122a..6deb17d3c3 100644
--- a/src/main/java/org/bukkit/craftbukkit/block/CraftEndGateway.java
+++ b/src/main/java/org/bukkit/craftbukkit/block/CraftEndGateway.java
@@ -6,66 +6,41 @@ import org.bukkit.Location;
 import org.bukkit.Material;
 import org.bukkit.block.Block;
 import org.bukkit.block.EndGateway;
-import org.bukkit.craftbukkit.CraftWorld;
 
-public class CraftEndGateway extends CraftBlockState implements EndGateway {
-
-    private final CraftWorld world;
-    private final TileEntityEndGateway gateway;
+public class CraftEndGateway extends CraftBlockEntityState<TileEntityEndGateway> implements EndGateway {
 
     public CraftEndGateway(Block block) {
-        super(block);
-
-        world = (CraftWorld) block.getWorld();
-        gateway = (TileEntityEndGateway) world.getTileEntityAt(getX(), getY(), getZ());
+        super(block, TileEntityEndGateway.class);
     }
 
     public CraftEndGateway(final Material material, TileEntityEndGateway te) {
-        super(material);
-        world = null;
-        this.gateway = te;
+        super(material, te);
     }
-    
+
     @Override
     public Location getExitLocation() {
-        BlockPosition pos = gateway.exitPortal;
-        return pos == null ? null : new Location(world, pos.getX(), pos.getY(), pos.getZ());
+        BlockPosition pos = this.getSnapshot().exitPortal;
+        return pos == null ? null : new Location(this.isPlaced() ? this.getWorld() : null, pos.getX(), pos.getY(), pos.getZ());
     }
 
     @Override
     public void setExitLocation(Location location) {
         if (location == null) {
-            gateway.exitPortal = null;
-        } else if (location.getWorld() != world) {
+            this.getSnapshot().exitPortal = null;
+        } else if (location.getWorld() != (this.isPlaced() ? this.getWorld() : null)) {
             throw new IllegalArgumentException("Cannot set exit location to different world");
         } else {
-            gateway.exitPortal = new BlockPosition(location.getBlockX(), location.getBlockY(), location.getBlockZ());
+            this.getSnapshot().exitPortal = new BlockPosition(location.getBlockX(), location.getBlockY(), location.getBlockZ());
         }
     }
 
     @Override
     public boolean isExactTeleport() {
-        return gateway.exactTeleport;
+        return this.getSnapshot().exactTeleport;
     }
 
     @Override
     public void setExactTeleport(boolean exact) {
-        gateway.exactTeleport = exact;
-    }
-
-    @Override
-    public boolean update(boolean force, boolean applyPhysics) {
-        boolean result = super.update(force, applyPhysics);
-
-        if (result) {
-            gateway.update();
-        }
-
-        return result;
-    }
-
-    @Override
-    public TileEntityEndGateway getTileEntity() {
-        return gateway;
+        this.getSnapshot().exactTeleport = exact;
     }
 }
diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftEnderChest.java b/src/main/java/org/bukkit/craftbukkit/block/CraftEnderChest.java
index 9c4b553a80..2004ee2f3a 100644
--- a/src/main/java/org/bukkit/craftbukkit/block/CraftEnderChest.java
+++ b/src/main/java/org/bukkit/craftbukkit/block/CraftEnderChest.java
@@ -1,33 +1,17 @@
 package org.bukkit.craftbukkit.block;
 
-import net.minecraft.server.TileEntity;
 import net.minecraft.server.TileEntityEnderChest;
 import org.bukkit.Material;
 import org.bukkit.block.Block;
 import org.bukkit.block.EnderChest;
-import org.bukkit.craftbukkit.CraftWorld;
 
-public class CraftEnderChest extends CraftBlockState implements EnderChest {
-
-    private final CraftWorld world;
-    private final TileEntityEnderChest chest;
+public class CraftEnderChest extends CraftBlockEntityState<TileEntityEnderChest> implements EnderChest {
 
     public CraftEnderChest(final Block block) {
-        super(block);
-
-        world = (CraftWorld) block.getWorld();
-        chest = (TileEntityEnderChest) world.getTileEntityAt(getX(), getY(), getZ());
+        super(block, TileEntityEnderChest.class);
     }
 
     public CraftEnderChest(final Material material, final TileEntityEnderChest te) {
-        super(material);
-
-        chest = te;
-        world = null;
-    }
-
-    @Override
-    public TileEntity getTileEntity() {
-        return chest;
+        super(material, te);
     }
 }
diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftFlowerPot.java b/src/main/java/org/bukkit/craftbukkit/block/CraftFlowerPot.java
index e6a5bc1ad0..c9097ac84b 100644
--- a/src/main/java/org/bukkit/craftbukkit/block/CraftFlowerPot.java
+++ b/src/main/java/org/bukkit/craftbukkit/block/CraftFlowerPot.java
@@ -1,37 +1,30 @@
 package org.bukkit.craftbukkit.block;
 
 import net.minecraft.server.ItemStack;
-import net.minecraft.server.TileEntity;
 import net.minecraft.server.TileEntityFlowerPot;
 import org.bukkit.Material;
 import org.bukkit.block.Block;
 import org.bukkit.block.FlowerPot;
-import org.bukkit.craftbukkit.CraftWorld;
 import org.bukkit.craftbukkit.inventory.CraftItemStack;
 import org.bukkit.material.MaterialData;
 
-public class CraftFlowerPot extends CraftBlockState implements FlowerPot {
+public class CraftFlowerPot extends CraftBlockEntityState<TileEntityFlowerPot> implements FlowerPot {
 
-    private final TileEntityFlowerPot pot;
     private MaterialData contents;
 
     public CraftFlowerPot(Block block) {
-        super(block);
-
-        pot = (TileEntityFlowerPot) ((CraftWorld) block.getWorld()).getTileEntityAt(getX(), getY(), getZ());
-        contents = (pot.getItem() == null) ? null : CraftItemStack.asBukkitCopy(pot.getContents()).getData();
+        super(block, TileEntityFlowerPot.class);
     }
 
     public CraftFlowerPot(Material material, TileEntityFlowerPot te) {
-        super(material);
-
-        pot = te;
-        contents = (pot.getItem() == null) ? null : CraftItemStack.asBukkitCopy(pot.getContents()).getData();
+        super(material, te);
     }
 
     @Override
-    public TileEntity getTileEntity() {
-        return pot;
+    public void load(TileEntityFlowerPot pot) {
+        super.load(pot);
+
+        contents = (pot.getItem() == null) ? null : CraftItemStack.asBukkitCopy(pot.getContents()).getData();
     }
 
     @Override
@@ -45,14 +38,9 @@ public class CraftFlowerPot extends CraftBlockState implements FlowerPot {
     }
 
     @Override
-    public boolean update(boolean force, boolean applyPhysics) {
-        boolean result = super.update(force, applyPhysics);
+    public void applyTo(TileEntityFlowerPot pot) {
+        super.applyTo(pot);
 
-        if (result) {
-            pot.setContents(contents == null ? ItemStack.a : CraftItemStack.asNMSCopy(contents.toItemStack(1)));
-            pot.update();
-        }
-
-        return result;
+        pot.setContents(contents == null ? ItemStack.a : CraftItemStack.asNMSCopy(contents.toItemStack(1)));
     }
 }
diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftFurnace.java b/src/main/java/org/bukkit/craftbukkit/block/CraftFurnace.java
index 9865ff06b1..fbde4433ea 100644
--- a/src/main/java/org/bukkit/craftbukkit/block/CraftFurnace.java
+++ b/src/main/java/org/bukkit/craftbukkit/block/CraftFurnace.java
@@ -4,67 +4,61 @@ import net.minecraft.server.TileEntityFurnace;
 import org.bukkit.Material;
 import org.bukkit.block.Block;
 import org.bukkit.block.Furnace;
-import org.bukkit.craftbukkit.CraftWorld;
 import org.bukkit.craftbukkit.inventory.CraftInventoryFurnace;
 import org.bukkit.inventory.FurnaceInventory;
 
-public class CraftFurnace extends CraftContainer implements Furnace {
-    private final TileEntityFurnace furnace;
+public class CraftFurnace extends CraftContainer<TileEntityFurnace> implements Furnace {
 
     public CraftFurnace(final Block block) {
-        super(block);
-
-        furnace = (TileEntityFurnace) ((CraftWorld) block.getWorld()).getTileEntityAt(getX(), getY(), getZ());
+        super(block, TileEntityFurnace.class);
     }
 
     public CraftFurnace(final Material material, final TileEntityFurnace te) {
         super(material, te);
-        furnace = te;
-    }
-
-    public FurnaceInventory getInventory() {
-        return new CraftInventoryFurnace(furnace);
     }
 
     @Override
-    public boolean update(boolean force, boolean applyPhysics) {
-        boolean result = super.update(force, applyPhysics);
+    public FurnaceInventory getSnapshotInventory() {
+        return new CraftInventoryFurnace(this.getSnapshot());
+    }
 
-        if (result) {
-            furnace.update();
+    @Override
+    public FurnaceInventory getInventory() {
+        if (!this.isPlaced()) {
+            return this.getSnapshotInventory();
         }
 
-        return result;
+        return new CraftInventoryFurnace(this.getTileEntity());
     }
 
+    @Override
     public short getBurnTime() {
-        return (short) furnace.getProperty(0);
+        return (short) this.getSnapshot().getProperty(0);
     }
 
+    @Override
     public void setBurnTime(short burnTime) {
-        furnace.setProperty(0, burnTime);
+        this.getSnapshot().setProperty(0, burnTime);
     }
 
+    @Override
     public short getCookTime() {
-        return (short) furnace.getProperty(2);
+        return (short) this.getSnapshot().getProperty(2);
     }
 
+    @Override
     public void setCookTime(short cookTime) {
-        furnace.setProperty(2, cookTime);
+        this.getSnapshot().setProperty(2, cookTime);
     }
 
     @Override
     public String getCustomName() {
+        TileEntityFurnace furnace = this.getSnapshot();
         return furnace.hasCustomName() ? furnace.getName() : null;
     }
 
     @Override
     public void setCustomName(String name) {
-        furnace.setCustomName(name);
-    }
-
-    @Override
-    public TileEntityFurnace getTileEntity() {
-        return furnace;
+        this.getSnapshot().setCustomName(name);
     }
 }
diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftHopper.java b/src/main/java/org/bukkit/craftbukkit/block/CraftHopper.java
index b7a04bd847..6566554ab6 100644
--- a/src/main/java/org/bukkit/craftbukkit/block/CraftHopper.java
+++ b/src/main/java/org/bukkit/craftbukkit/block/CraftHopper.java
@@ -4,42 +4,30 @@ import net.minecraft.server.TileEntityHopper;
 import org.bukkit.Material;
 import org.bukkit.block.Block;
 import org.bukkit.block.Hopper;
-import org.bukkit.craftbukkit.CraftWorld;
 import org.bukkit.craftbukkit.inventory.CraftInventory;
 import org.bukkit.inventory.Inventory;
 
-public class CraftHopper extends CraftLootable implements Hopper {
-    private final TileEntityHopper hopper;
+public class CraftHopper extends CraftLootable<TileEntityHopper> implements Hopper {
 
     public CraftHopper(final Block block) {
-        super(block);
-
-        hopper = (TileEntityHopper) ((CraftWorld) block.getWorld()).getTileEntityAt(getX(), getY(), getZ());
+        super(block, TileEntityHopper.class);
     }
 
     public CraftHopper(final Material material, final TileEntityHopper te) {
         super(material, te);
-
-        hopper = te;
-    }
-
-    public Inventory getInventory() {
-        return new CraftInventory(hopper);
     }
 
     @Override
-    public boolean update(boolean force, boolean applyPhysics) {
-        boolean result = super.update(force, applyPhysics);
+    public Inventory getSnapshotInventory() {
+        return new CraftInventory(this.getSnapshot());
+    }
 
-        if (result) {
-            hopper.update();
+    @Override
+    public Inventory getInventory() {
+        if (!this.isPlaced()) {
+            return this.getSnapshotInventory();
         }
 
-        return result;
-    }
-
-    @Override
-    public TileEntityHopper getTileEntity() {
-        return hopper;
+        return new CraftInventory(this.getTileEntity());
     }
 }
diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftJukebox.java b/src/main/java/org/bukkit/craftbukkit/block/CraftJukebox.java
index 25365f1189..d259cfb82f 100644
--- a/src/main/java/org/bukkit/craftbukkit/block/CraftJukebox.java
+++ b/src/main/java/org/bukkit/craftbukkit/block/CraftJukebox.java
@@ -1,7 +1,11 @@
 package org.bukkit.craftbukkit.block;
 
-import net.minecraft.server.*;
+import net.minecraft.server.BlockJukeBox;
 import net.minecraft.server.BlockJukeBox.TileEntityRecordPlayer;
+import net.minecraft.server.BlockPosition;
+import net.minecraft.server.Blocks;
+import net.minecraft.server.ItemStack;
+import net.minecraft.server.TileEntity;
 import org.bukkit.Effect;
 import org.bukkit.Material;
 import org.bukkit.block.Block;
@@ -9,26 +13,41 @@ import org.bukkit.block.Jukebox;
 import org.bukkit.craftbukkit.CraftWorld;
 import org.bukkit.craftbukkit.util.CraftMagicNumbers;
 
-public class CraftJukebox extends CraftBlockState implements Jukebox {
-    private final CraftWorld world;
-    private final TileEntityRecordPlayer jukebox;
+public class CraftJukebox extends CraftBlockEntityState<TileEntityRecordPlayer> implements Jukebox {
 
     public CraftJukebox(final Block block) {
-        super(block);
-
-        world = (CraftWorld) block.getWorld();
-        jukebox = (TileEntityRecordPlayer) world.getTileEntityAt(getX(), getY(), getZ());
+        super(block, TileEntityRecordPlayer.class);
     }
 
     public CraftJukebox(final Material material, TileEntityRecordPlayer te) {
-        super(material);
-        world = null;
-        jukebox = te;
+        super(material, te);
+    }
+
+    @Override
+    public boolean update(boolean force, boolean applyPhysics) {
+        boolean result = super.update(force, applyPhysics);
+
+        if (result && this.isPlaced() && this.getType() == Material.JUKEBOX) {
+            CraftWorld world = (CraftWorld) this.getWorld();
+            Material record = this.getPlaying();
+            if (record == Material.AIR) {
+                world.getHandle().setTypeAndData(new BlockPosition(this.getX(), this.getY(), this.getZ()),
+                    Blocks.JUKEBOX.getBlockData()
+                        .set(BlockJukeBox.HAS_RECORD, false), 3);
+            } else {
+                world.getHandle().setTypeAndData(new BlockPosition(this.getX(), this.getY(), this.getZ()),
+                    Blocks.JUKEBOX.getBlockData()
+                        .set(BlockJukeBox.HAS_RECORD, true), 3);
+            }
+            world.playEffect(this.getLocation(), Effect.RECORD_PLAY, record.getId());
+        }
+
+        return result;
     }
 
     @Override
     public Material getPlaying() {
-        ItemStack record = jukebox.getRecord();
+        ItemStack record = this.getSnapshot().getRecord();
         if (record.isEmpty()) {
             return Material.AIR;
         }
@@ -41,38 +60,29 @@ public class CraftJukebox extends CraftBlockState implements Jukebox {
             record = Material.AIR;
         }
 
-        jukebox.setRecord(new ItemStack(CraftMagicNumbers.getItem(record), 1));
-        if (!isPlaced()) {
-            return;
-        }
-        jukebox.update();
+        this.getSnapshot().setRecord(new ItemStack(CraftMagicNumbers.getItem(record), 1));
         if (record == Material.AIR) {
             setRawData((byte) 0);
-            world.getHandle().setTypeAndData(new BlockPosition(getX(), getY(), getZ()),
-                Blocks.JUKEBOX.getBlockData()
-                    .set(BlockJukeBox.HAS_RECORD, false), 3);
         } else {
             setRawData((byte) 1);
-            world.getHandle().setTypeAndData(new BlockPosition(getX(), getY(), getZ()),
-                Blocks.JUKEBOX.getBlockData()
-                    .set(BlockJukeBox.HAS_RECORD, true), 3);
         }
-        world.playEffect(getLocation(), Effect.RECORD_PLAY, record.getId());
     }
 
+    @Override
     public boolean isPlaying() {
         return getRawData() == 1;
     }
 
+    @Override
     public boolean eject() {
         requirePlaced();
-        boolean result = isPlaying();
+        TileEntity tileEntity = this.getTileEntityFromWorld();
+        if (!(tileEntity instanceof TileEntityRecordPlayer)) return false;
+
+        TileEntityRecordPlayer jukebox = (TileEntityRecordPlayer) tileEntity;
+        boolean result = !jukebox.getRecord().isEmpty();
+        CraftWorld world = (CraftWorld) this.getWorld();
         ((BlockJukeBox) Blocks.JUKEBOX).dropRecord(world.getHandle(), new BlockPosition(getX(), getY(), getZ()), null);
         return result;
     }
-
-    @Override
-    public TileEntityRecordPlayer getTileEntity() {
-        return jukebox;
-    }
 }
diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftLootable.java b/src/main/java/org/bukkit/craftbukkit/block/CraftLootable.java
index c75b102417..306a47ba83 100644
--- a/src/main/java/org/bukkit/craftbukkit/block/CraftLootable.java
+++ b/src/main/java/org/bukkit/craftbukkit/block/CraftLootable.java
@@ -4,31 +4,25 @@ import net.minecraft.server.TileEntityLootable;
 import org.bukkit.Material;
 import org.bukkit.Nameable;
 import org.bukkit.block.Block;
-import org.bukkit.craftbukkit.CraftWorld;
 
-public class CraftLootable extends CraftContainer implements Nameable {
+public abstract class CraftLootable<T extends TileEntityLootable> extends CraftContainer<T> implements Nameable {
 
-    private final TileEntityLootable te;
-
-    public CraftLootable(Block block) {
-        super(block);
-
-        te = (TileEntityLootable) ((CraftWorld) block.getWorld()).getTileEntityAt(getX(), getY(), getZ());
+    public CraftLootable(Block block, Class<T> tileEntityClass) {
+        super(block, tileEntityClass);
     }
 
-    public CraftLootable(Material material, TileEntityLootable tileEntity) {
+    public CraftLootable(Material material, T tileEntity) {
         super(material, tileEntity);
-
-        te = tileEntity;
     }
 
     @Override
     public String getCustomName() {
-        return te.hasCustomName() ? te.getName() : null;
+        T lootable = this.getSnapshot();
+        return lootable.hasCustomName() ? lootable.getName() : null;
     }
 
     @Override
     public void setCustomName(String name) {
-        te.setCustomName(name);
+        this.getSnapshot().setCustomName(name);
     }
 }
diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftNoteBlock.java b/src/main/java/org/bukkit/craftbukkit/block/CraftNoteBlock.java
index 0507f3b804..880831d417 100644
--- a/src/main/java/org/bukkit/craftbukkit/block/CraftNoteBlock.java
+++ b/src/main/java/org/bukkit/craftbukkit/block/CraftNoteBlock.java
@@ -11,43 +11,43 @@ import org.bukkit.block.NoteBlock;
 import org.bukkit.craftbukkit.CraftWorld;
 import org.bukkit.craftbukkit.util.CraftMagicNumbers;
 
-public class CraftNoteBlock extends CraftBlockState implements NoteBlock {
-    private final CraftWorld world;
-    private final TileEntityNote note;
+public class CraftNoteBlock extends CraftBlockEntityState<TileEntityNote> implements NoteBlock {
 
     public CraftNoteBlock(final Block block) {
-        super(block);
-
-        world = (CraftWorld) block.getWorld();
-        note = (TileEntityNote) world.getTileEntityAt(getX(), getY(), getZ());
+        super(block, TileEntityNote.class);
     }
 
     public CraftNoteBlock(final Material material, final TileEntityNote te) {
-        super(material);
-        world = null;
-        note = te;
+        super(material, te);
     }
 
+    @Override
     public Note getNote() {
-        return new Note(note.note);
+        return new Note(this.getSnapshot().note);
     }
 
+    @Override
     public byte getRawNote() {
-        return note.note;
+        return this.getSnapshot().note;
     }
 
-    public void setNote(Note n) {
-        note.note = n.getId();
+    @Override
+    public void setNote(Note note) {
+        this.getSnapshot().note = note.getId();
     }
 
-    public void setRawNote(byte n) {
-        note.note = n;
+    @Override
+    public void setRawNote(byte note) {
+        this.getSnapshot().note = note;
     }
 
+    @Override
     public boolean play() {
         Block block = getBlock();
 
         if (block.getType() == Material.NOTE_BLOCK) {
+            TileEntityNote note = (TileEntityNote) this.getTileEntityFromWorld();
+            CraftWorld world = (CraftWorld) this.getWorld();
             note.play(world.getHandle(), new BlockPosition(getX(), getY(), getZ()));
             return true;
         } else {
@@ -60,6 +60,7 @@ public class CraftNoteBlock extends CraftBlockState implements NoteBlock {
         Block block = getBlock();
 
         if (block.getType() == Material.NOTE_BLOCK) {
+            CraftWorld world = (CraftWorld) this.getWorld();
             world.getHandle().playBlockAction(new BlockPosition(getX(), getY(), getZ()), CraftMagicNumbers.getBlock(block), instrument, note);
             return true;
         } else {
@@ -72,15 +73,11 @@ public class CraftNoteBlock extends CraftBlockState implements NoteBlock {
         Block block = getBlock();
 
         if (block.getType() == Material.NOTE_BLOCK) {
+            CraftWorld world = (CraftWorld) this.getWorld();
             world.getHandle().playBlockAction(new BlockPosition(getX(), getY(), getZ()), CraftMagicNumbers.getBlock(block), instrument.getType(), note.getId());
             return true;
         } else {
             return false;
         }
     }
-
-    @Override
-    public TileEntityNote getTileEntity() {
-        return note;
-    }
 }
diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftShulkerBox.java b/src/main/java/org/bukkit/craftbukkit/block/CraftShulkerBox.java
index 788c602631..c029a12441 100644
--- a/src/main/java/org/bukkit/craftbukkit/block/CraftShulkerBox.java
+++ b/src/main/java/org/bukkit/craftbukkit/block/CraftShulkerBox.java
@@ -1,47 +1,43 @@
 package org.bukkit.craftbukkit.block;
 
 import net.minecraft.server.BlockShulkerBox;
-import net.minecraft.server.TileEntity;
 import net.minecraft.server.TileEntityShulkerBox;
 import org.bukkit.DyeColor;
 import org.bukkit.Material;
 import org.bukkit.block.Block;
 import org.bukkit.block.ShulkerBox;
-import org.bukkit.craftbukkit.CraftWorld;
 import org.bukkit.craftbukkit.inventory.CraftInventory;
+import org.bukkit.craftbukkit.util.CraftMagicNumbers;
 import org.bukkit.inventory.Inventory;
 
-public class CraftShulkerBox extends CraftLootable implements ShulkerBox {
-
-    private final CraftWorld world;
-    private final TileEntityShulkerBox box;
+public class CraftShulkerBox extends CraftLootable<TileEntityShulkerBox> implements ShulkerBox {
 
     public CraftShulkerBox(final Block block) {
-        super(block);
-
-        world = (CraftWorld) block.getWorld();
-        box = (TileEntityShulkerBox) world.getTileEntityAt(getX(), getY(), getZ());
+        super(block, TileEntityShulkerBox.class);
     }
 
     public CraftShulkerBox(final Material material, final TileEntityShulkerBox te) {
         super(material, te);
-
-        box = te;
-        world = null;
     }
 
     @Override
-    public TileEntity getTileEntity() {
-        return box;
+    public Inventory getSnapshotInventory() {
+        return new CraftInventory(this.getSnapshot());
     }
 
     @Override
     public Inventory getInventory() {
-        return new CraftInventory(box);
+        if (!this.isPlaced()) {
+            return this.getSnapshotInventory();
+        }
+
+        return new CraftInventory(this.getTileEntity());
     }
 
     @Override
     public DyeColor getColor() {
-        return DyeColor.getByWoolData((byte) ((BlockShulkerBox) box.getBlock()).color.getColorIndex());
+        net.minecraft.server.Block block = CraftMagicNumbers.getBlock(this.getType());
+
+        return DyeColor.getByWoolData((byte) ((BlockShulkerBox) block).color.getColorIndex());
     }
 }
diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftSign.java b/src/main/java/org/bukkit/craftbukkit/block/CraftSign.java
index 42a6f9a7db..7a8d445299 100644
--- a/src/main/java/org/bukkit/craftbukkit/block/CraftSign.java
+++ b/src/main/java/org/bukkit/craftbukkit/block/CraftSign.java
@@ -6,52 +6,49 @@ import net.minecraft.server.TileEntitySign;
 import org.bukkit.Material;
 import org.bukkit.block.Block;
 import org.bukkit.block.Sign;
-import org.bukkit.craftbukkit.CraftWorld;
 import org.bukkit.craftbukkit.util.CraftChatMessage;
 
-public class CraftSign extends CraftBlockState implements Sign {
-    private final TileEntitySign sign;
-    private final String[] lines;
+public class CraftSign extends CraftBlockEntityState<TileEntitySign> implements Sign {
+
+    private String[] lines;
 
     public CraftSign(final Block block) {
-        super(block);
-
-        CraftWorld world = (CraftWorld) block.getWorld();
-        sign = (TileEntitySign) world.getTileEntityAt(getX(), getY(), getZ());
-        lines = new String[sign.lines.length];
-        System.arraycopy(revertComponents(sign.lines), 0, lines, 0, lines.length);
+        super(block, TileEntitySign.class);
     }
 
     public CraftSign(final Material material, final TileEntitySign te) {
-        super(material);
-        sign = te;
+        super(material, te);
+    }
+
+    @Override
+    public void load(TileEntitySign sign) {
+        super.load(sign);
+
         lines = new String[sign.lines.length];
         System.arraycopy(revertComponents(sign.lines), 0, lines, 0, lines.length);
     }
 
+    @Override
     public String[] getLines() {
         return lines;
     }
 
+    @Override
     public String getLine(int index) throws IndexOutOfBoundsException {
         return lines[index];
     }
 
+    @Override
     public void setLine(int index, String line) throws IndexOutOfBoundsException {
         lines[index] = line;
     }
 
     @Override
-    public boolean update(boolean force, boolean applyPhysics) {
-        boolean result = super.update(force, applyPhysics);
+    public void applyTo(TileEntitySign sign) {
+        super.applyTo(sign);
 
-        if (result) {
-            IChatBaseComponent[] newLines = sanitizeLines(lines);
-            System.arraycopy(newLines, 0, sign.lines, 0, 4);
-            sign.update();
-        }
-
-        return result;
+        IChatBaseComponent[] newLines = sanitizeLines(lines);
+        System.arraycopy(newLines, 0, sign.lines, 0, 4);
     }
 
     public static IChatBaseComponent[] sanitizeLines(String[] lines) {
@@ -79,9 +76,4 @@ public class CraftSign extends CraftBlockState implements Sign {
     private static String revertComponent(IChatBaseComponent component) {
         return CraftChatMessage.fromComponent(component);
     }
-
-    @Override
-    public TileEntitySign getTileEntity() {
-        return sign;
-    }
 }
diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftSkull.java b/src/main/java/org/bukkit/craftbukkit/block/CraftSkull.java
index 89e4e72570..f2865688a5 100644
--- a/src/main/java/org/bukkit/craftbukkit/block/CraftSkull.java
+++ b/src/main/java/org/bukkit/craftbukkit/block/CraftSkull.java
@@ -12,28 +12,26 @@ import org.bukkit.SkullType;
 import org.bukkit.block.Block;
 import org.bukkit.block.BlockFace;
 import org.bukkit.block.Skull;
-import org.bukkit.craftbukkit.CraftWorld;
 
-public class CraftSkull extends CraftBlockState implements Skull {
+public class CraftSkull extends CraftBlockEntityState<TileEntitySkull> implements Skull {
+
     private static final int MAX_OWNER_LENGTH = 16;
-    private final TileEntitySkull skull;
     private GameProfile profile;
     private SkullType skullType;
     private byte rotation;
 
     public CraftSkull(final Block block) {
-        super(block);
-
-        CraftWorld world = (CraftWorld) block.getWorld();
-        skull = (TileEntitySkull) world.getTileEntityAt(getX(), getY(), getZ());
-        profile = skull.getGameProfile();
-        skullType = getSkullType(skull.getSkullType());
-        rotation = (byte) skull.rotation;
+        super(block, TileEntitySkull.class);
     }
 
     public CraftSkull(final Material material, final TileEntitySkull te) {
-        super(material);
-        skull = te;
+        super(material, te);
+    }
+
+    @Override
+    public void load(TileEntitySkull skull) {
+        super.load(skull);
+
         profile = skull.getGameProfile();
         skullType = getSkullType(skull.getSkullType());
         rotation = (byte) skull.rotation;
@@ -153,14 +151,17 @@ public class CraftSkull extends CraftBlockState implements Skull {
         }
     }
 
+    @Override
     public boolean hasOwner() {
         return profile != null;
     }
 
+    @Override
     public String getOwner() {
         return hasOwner() ? profile.getName() : null;
     }
 
+    @Override
     public boolean setOwner(String name) {
         if (name == null || name.length() > MAX_OWNER_LENGTH) {
             return false;
@@ -205,18 +206,22 @@ public class CraftSkull extends CraftBlockState implements Skull {
         this.profile = new GameProfile(player.getUniqueId(), player.getName());
     }
 
+    @Override
     public BlockFace getRotation() {
-    	return getBlockFace(rotation);
+        return getBlockFace(rotation);
     }
 
+    @Override
     public void setRotation(BlockFace rotation) {
         this.rotation = getBlockFace(rotation);
     }
 
+    @Override
     public SkullType getSkullType() {
         return skullType;
     }
 
+    @Override
     public void setSkullType(SkullType skullType) {
         this.skullType = skullType;
 
@@ -226,25 +231,15 @@ public class CraftSkull extends CraftBlockState implements Skull {
     }
 
     @Override
-    public boolean update(boolean force, boolean applyPhysics) {
-        boolean result = super.update(force, applyPhysics);
+    public void applyTo(TileEntitySkull skull) {
+        super.applyTo(skull);
 
-        if (result) {
-            if (skullType == SkullType.PLAYER) {
-                skull.setGameProfile(profile);
-            } else {
-                skull.setSkullType(getSkullType(skullType));
-            }
-
-            skull.setRotation(rotation);
-            skull.update();
+        if (skullType == SkullType.PLAYER) {
+            skull.setGameProfile(profile);
+        } else {
+            skull.setSkullType(getSkullType(skullType));
         }
 
-        return result;
-    }
-
-    @Override
-    public TileEntitySkull getTileEntity() {
-        return skull;
+        skull.setRotation(rotation);
     }
 }
diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftStructureBlock.java b/src/main/java/org/bukkit/craftbukkit/block/CraftStructureBlock.java
index 36520729d8..ecf12ee380 100644
--- a/src/main/java/org/bukkit/craftbukkit/block/CraftStructureBlock.java
+++ b/src/main/java/org/bukkit/craftbukkit/block/CraftStructureBlock.java
@@ -1,29 +1,16 @@
 package org.bukkit.craftbukkit.block;
 
-import net.minecraft.server.TileEntity;
 import net.minecraft.server.TileEntityStructure;
 import org.bukkit.Material;
 import org.bukkit.block.Block;
-import org.bukkit.craftbukkit.CraftWorld;
 
-public class CraftStructureBlock extends CraftBlockState {
-
-    private final TileEntityStructure structure;
+public class CraftStructureBlock extends CraftBlockEntityState<TileEntityStructure> {
 
     public CraftStructureBlock(Block block) {
-        super(block);
-
-        this.structure = (TileEntityStructure) ((CraftWorld) block.getWorld()).getTileEntityAt(getX(), getY(), getZ());
+        super(block, TileEntityStructure.class);
     }
 
     public CraftStructureBlock(Material material, TileEntityStructure structure) {
-        super(material);
-
-        this.structure = structure;
-    }
-
-    @Override
-    public TileEntity getTileEntity() {
-        return structure;
+        super(material, structure);
     }
 }
diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaBlockState.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaBlockState.java
index 03d0f5c3c1..fe874e0da1 100644
--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaBlockState.java
+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaBlockState.java
@@ -34,7 +34,7 @@ import org.bukkit.block.BlockState;
 import org.bukkit.configuration.serialization.DelegateDeserialization;
 import org.bukkit.craftbukkit.block.CraftBanner;
 import org.bukkit.craftbukkit.block.CraftBeacon;
-import org.bukkit.craftbukkit.block.CraftBlockState;
+import org.bukkit.craftbukkit.block.CraftBlockEntityState;
 import org.bukkit.craftbukkit.block.CraftBrewingStand;
 import org.bukkit.craftbukkit.block.CraftChest;
 import org.bukkit.craftbukkit.block.CraftCommandBlock;
@@ -384,7 +384,6 @@ public class CraftMetaBlockState extends CraftMetaItem implements BlockStateMeta
             }
             return new CraftComparator(material, (TileEntityComparator) te);
         case PISTON_BASE:
-            
         default:
             throw new IllegalStateException("Missing blockState for " + material);
         }
@@ -393,70 +392,68 @@ public class CraftMetaBlockState extends CraftMetaItem implements BlockStateMeta
     @Override
     public void setBlockState(BlockState blockState) {
         Validate.notNull(blockState, "blockState must not be null");
-        TileEntity te = ((CraftBlockState) blockState).getTileEntity();
-        Validate.notNull(te, "Invalid tile for " + blockState);
 
         boolean valid;
         switch (material) {
         case SIGN:
         case SIGN_POST:
         case WALL_SIGN:
-            valid = te instanceof TileEntitySign;
+            valid = blockState instanceof CraftSign;
             break;
         case CHEST:
         case TRAPPED_CHEST:
-            valid = te instanceof TileEntityChest;
+            valid = blockState instanceof CraftChest;
             break;
         case BURNING_FURNACE:
         case FURNACE:
-            valid = te instanceof TileEntityFurnace;
+            valid = blockState instanceof CraftFurnace;
             break;
         case DISPENSER:
-            valid = te instanceof TileEntityDispenser;
+            valid = blockState instanceof CraftDispenser;
             break;
         case DROPPER:
-            valid = te instanceof TileEntityDropper;
+            valid = blockState instanceof CraftDropper;
             break;
         case END_GATEWAY:
-            valid = te instanceof TileEntityEndGateway;
+            valid = blockState instanceof CraftEndGateway;
             break;
         case HOPPER:
-            valid = te instanceof TileEntityHopper;
+            valid = blockState instanceof CraftHopper;
             break;
         case MOB_SPAWNER:
-            valid = te instanceof TileEntityMobSpawner;
+            valid = blockState instanceof CraftCreatureSpawner;
             break;
         case NOTE_BLOCK:
-            valid = te instanceof TileEntityNote;
+            valid = blockState instanceof CraftNoteBlock;
             break;
         case JUKEBOX:
-            valid = te instanceof BlockJukeBox.TileEntityRecordPlayer;
+            valid = blockState instanceof CraftJukebox;
             break;
         case BREWING_STAND_ITEM:
-            valid = te instanceof TileEntityBrewingStand;
+            valid = blockState instanceof CraftBrewingStand;
             break;
         case SKULL:
-            valid = te instanceof TileEntitySkull;
+            valid = blockState instanceof CraftSkull;
             break;
         case COMMAND:
         case COMMAND_REPEATING:
         case COMMAND_CHAIN:
-            valid = te instanceof TileEntityCommand;
+            valid = blockState instanceof CraftCommandBlock;
             break;
         case BEACON:
-            valid = te instanceof TileEntityBeacon;
+            valid = blockState instanceof CraftBeacon;
             break;
         case SHIELD:
         case BANNER:
         case WALL_BANNER:
         case STANDING_BANNER:
-            valid = te instanceof TileEntityBanner;
+            valid = blockState instanceof CraftBanner;
             break;
         case FLOWER_POT_ITEM:
-            valid = te instanceof TileEntityFlowerPot;
+            valid = blockState instanceof CraftFlowerPot;
             break;
         case STRUCTURE_BLOCK:
-            valid = te instanceof TileEntityStructure;
+            valid = blockState instanceof CraftStructureBlock;
             break;
         case WHITE_SHULKER_BOX:
         case ORANGE_SHULKER_BOX:
@@ -474,20 +471,20 @@ public class CraftMetaBlockState extends CraftMetaItem implements BlockStateMeta
         case GREEN_SHULKER_BOX:
         case RED_SHULKER_BOX:
         case BLACK_SHULKER_BOX:
-            valid = te instanceof TileEntityShulkerBox;
+            valid = blockState instanceof CraftShulkerBox;
             break;
         case ENCHANTMENT_TABLE:
-            valid = te instanceof TileEntityEnchantTable;
+            valid = blockState instanceof CraftEnchantingTable;
             break;
         case ENDER_CHEST:
-            valid = te instanceof TileEntityEnderChest;
+            valid = blockState instanceof CraftEnderChest;
             break;
         case DAYLIGHT_DETECTOR:
         case DAYLIGHT_DETECTOR_INVERTED:
-            valid = te instanceof TileEntityLightDetector;
+            valid = blockState instanceof CraftDaylightDetector;
             break;
         case REDSTONE_COMPARATOR:
-            valid = te instanceof TileEntityComparator;
+            valid = blockState instanceof CraftComparator;
             break;
         default:
             valid = false;
@@ -496,7 +493,6 @@ public class CraftMetaBlockState extends CraftMetaItem implements BlockStateMeta
 
         Validate.isTrue(valid, "Invalid blockState for " + material);
 
-        blockEntityTag = new NBTTagCompound();
-        te.save(blockEntityTag);
+        blockEntityTag = ((CraftBlockEntityState) blockState).getSnapshotNBT();
     }
 }