diff --git a/src/main/java/com/minelittlepony/unicopia/ability/ChangelingDisguiseAbility.java b/src/main/java/com/minelittlepony/unicopia/ability/ChangelingDisguiseAbility.java
index b8c27e45..0b443adc 100644
--- a/src/main/java/com/minelittlepony/unicopia/ability/ChangelingDisguiseAbility.java
+++ b/src/main/java/com/minelittlepony/unicopia/ability/ChangelingDisguiseAbility.java
@@ -4,10 +4,11 @@ package com.minelittlepony.unicopia.ability;
 import org.jetbrains.annotations.Nullable;
 
 import com.minelittlepony.unicopia.ability.data.Hit;
-import com.minelittlepony.unicopia.ability.magic.spell.DisguiseSpell;
+import com.minelittlepony.unicopia.ability.magic.SpellPredicate;
+import com.minelittlepony.unicopia.ability.magic.spell.AbstractDisguiseSpell;
 import com.minelittlepony.unicopia.ability.magic.spell.effect.SpellType;
 import com.minelittlepony.unicopia.ability.magic.spell.trait.SpellTraits;
-import com.minelittlepony.unicopia.entity.behaviour.Disguise;
+import com.minelittlepony.unicopia.entity.behaviour.EntityAppearance;
 import com.minelittlepony.unicopia.entity.player.Pony;
 import com.minelittlepony.unicopia.particle.UParticles;
 import com.minelittlepony.unicopia.util.RayTraceHelper;
@@ -46,9 +47,9 @@ public class ChangelingDisguiseAbility extends ChangelingFeedAbility {
         Entity looked = trace.getEntity().map(e -> {
             return e instanceof PlayerEntity ? Pony.of((PlayerEntity)e)
                     .getSpellSlot()
-                    .get(SpellType.DISGUISE, true)
-                    .map(DisguiseSpell::getDisguise)
-                    .map(Disguise::getAppearance)
+                    .get(SpellPredicate.IS_DISGUISE, true)
+                    .map(AbstractDisguiseSpell::getDisguise)
+                    .map(EntityAppearance::getAppearance)
                     .orElse(e) : e;
         }).orElseGet(() -> trace.getBlockPos().map(pos -> {
             if (!iplayer.getWorld().isAir(pos)) {
@@ -59,8 +60,8 @@ public class ChangelingDisguiseAbility extends ChangelingFeedAbility {
 
         player.getEntityWorld().playSound(null, player.getBlockPos(), SoundEvents.ENTITY_PARROT_IMITATE_RAVAGER, SoundCategory.PLAYERS, 1.4F, 0.4F);
 
-        iplayer.getSpellSlot().get(SpellType.DISGUISE, true)
-            .orElseGet(() -> SpellType.DISGUISE.apply(iplayer, SpellTraits.EMPTY))
+        iplayer.getSpellSlot().get(SpellType.CHANGELING_DISGUISE, true)
+            .orElseGet(() -> SpellType.CHANGELING_DISGUISE.apply(iplayer, SpellTraits.EMPTY))
             .setDisguise(looked);
 
         if (!player.isCreative()) {
diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/SpellPredicate.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/SpellPredicate.java
index cf1e58cf..9c0be101 100644
--- a/src/main/java/com/minelittlepony/unicopia/ability/magic/SpellPredicate.java
+++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/SpellPredicate.java
@@ -2,6 +2,7 @@ package com.minelittlepony.unicopia.ability.magic;
 
 import java.util.function.Predicate;
 
+import com.minelittlepony.unicopia.ability.magic.spell.AbstractDisguiseSpell;
 import com.minelittlepony.unicopia.ability.magic.spell.ProjectileSpell;
 import com.minelittlepony.unicopia.ability.magic.spell.Spell;
 
@@ -10,6 +11,8 @@ public interface SpellPredicate<T extends Spell> extends Predicate<Spell> {
 
     SpellPredicate<ProjectileSpell> HAS_PROJECTILE_EVENTS = s -> s instanceof ProjectileSpell;
 
+    SpellPredicate<AbstractDisguiseSpell> IS_DISGUISE = s -> s instanceof AbstractDisguiseSpell;
+
     default boolean isOn(Caster<?> caster) {
         return caster.getSpellSlot().get(this, false).isPresent();
     }
diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/AbstractDisguiseSpell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/AbstractDisguiseSpell.java
new file mode 100644
index 00000000..e6e03455
--- /dev/null
+++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/AbstractDisguiseSpell.java
@@ -0,0 +1,76 @@
+package com.minelittlepony.unicopia.ability.magic.spell;
+
+import java.util.Optional;
+
+import com.minelittlepony.unicopia.ability.magic.Caster;
+import com.minelittlepony.unicopia.ability.magic.spell.effect.AbstractSpell;
+import com.minelittlepony.unicopia.ability.magic.spell.effect.SpellType;
+import com.minelittlepony.unicopia.ability.magic.spell.trait.SpellTraits;
+import com.minelittlepony.unicopia.entity.behaviour.Disguise;
+import com.minelittlepony.unicopia.entity.behaviour.EntityAppearance;
+import com.minelittlepony.unicopia.entity.player.Pony;
+import com.minelittlepony.unicopia.projectile.ProjectileImpactListener;
+
+import net.minecraft.entity.projectile.ProjectileEntity;
+import net.minecraft.nbt.NbtCompound;
+
+/**
+ * Shapeshifts the player.
+ * <p>
+ */
+public abstract class AbstractDisguiseSpell extends AbstractSpell implements Disguise, ProjectileImpactListener {
+
+    private final EntityAppearance disguise = new EntityAppearance();
+
+    public AbstractDisguiseSpell(SpellType<?> type, SpellTraits traits) {
+        super(type, traits);
+    }
+
+    @Override
+    public void onDestroyed(Caster<?> caster) {
+        caster.getEntity().calculateDimensions();
+        caster.getEntity().setInvisible(false);
+        if (caster instanceof Pony) {
+            ((Pony) caster).setInvisible(false);
+        }
+        disguise.remove();
+    }
+
+    @Override
+    public EntityAppearance getDisguise() {
+        return disguise;
+    }
+
+    @Override
+    public boolean onProjectileImpact(ProjectileEntity projectile) {
+        return disguise.getAppearance() == projectile;
+    }
+
+    @Override
+    public boolean tick(Caster<?> source, Situation situation) {
+        return situation == Situation.BODY && update(source, true);
+    }
+
+    @Override
+    public void setDead() {
+        super.setDead();
+        disguise.remove();
+    }
+
+    @Override
+    public void toNBT(NbtCompound compound) {
+        super.toNBT(compound);
+        disguise.toNBT(compound);
+    }
+
+    @Override
+    public void fromNBT(NbtCompound compound) {
+        super.fromNBT(compound);
+        disguise.fromNBT(compound);
+    }
+
+    @Override
+    public Optional<EntityAppearance> getAppearance() {
+        return Optional.ofNullable(disguise);
+    }
+}
diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/ChangelingDisguiseSpell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/ChangelingDisguiseSpell.java
new file mode 100644
index 00000000..192d9412
--- /dev/null
+++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/ChangelingDisguiseSpell.java
@@ -0,0 +1,98 @@
+package com.minelittlepony.unicopia.ability.magic.spell;
+
+import java.util.Optional;
+
+import com.minelittlepony.unicopia.ability.magic.Caster;
+import com.minelittlepony.unicopia.ability.magic.Suppressable;
+import com.minelittlepony.unicopia.ability.magic.spell.effect.SpellType;
+import com.minelittlepony.unicopia.ability.magic.spell.trait.SpellTraits;
+import com.minelittlepony.unicopia.ability.magic.spell.trait.Trait;
+import com.minelittlepony.unicopia.entity.behaviour.EntityAppearance;
+import com.minelittlepony.unicopia.entity.player.Pony;
+import com.minelittlepony.unicopia.particle.MagicParticleEffect;
+import com.minelittlepony.unicopia.particle.UParticles;
+import net.minecraft.entity.Entity;
+import net.minecraft.entity.LivingEntity;
+import net.minecraft.nbt.NbtCompound;
+
+/**
+ * Shapeshifts the player.
+ * <p>
+ * Internal. Used by the changeling ability.
+ */
+public class ChangelingDisguiseSpell extends AbstractDisguiseSpell implements Suppressable {
+
+    private int suppressionCounter;
+
+    public ChangelingDisguiseSpell(SpellType<?> type, SpellTraits traits) {
+        super(type, traits);
+    }
+
+    @Override
+    public boolean isVulnerable(Caster<?> otherSource, Spell other) {
+        return suppressionCounter <= otherSource.getLevel().get();
+    }
+
+    @Override
+    public void onSuppressed(Caster<?> otherSource, float time) {
+        time /= getTraits().getOrDefault(Trait.STRENGTH, 1);
+        suppressionCounter = (int)(100 * time);
+        setDirty();
+    }
+
+    @Override
+    public boolean isSuppressed() {
+        return suppressionCounter > 0;
+    }
+
+    @Override
+    public boolean update(Caster<?> source, boolean tick) {
+        if (source.isClient()) {
+            if (isSuppressed()) {
+                source.spawnParticles(MagicParticleEffect.UNICORN, 5);
+                source.spawnParticles(UParticles.CHANGELING_MAGIC, 5);
+            } else if (source.getWorld().random.nextInt(30) == 0) {
+                source.spawnParticles(UParticles.CHANGELING_MAGIC, 2);
+            }
+        }
+
+        LivingEntity owner = source.getMaster();
+
+        Entity entity = getDisguise().getAppearance();
+
+        if (isSuppressed()) {
+            suppressionCounter--;
+
+            owner.setInvisible(false);
+            if (source instanceof Pony) {
+                ((Pony)source).setInvisible(false);
+            }
+
+            if (entity != null) {
+                entity.setInvisible(true);
+                entity.setPos(entity.getX(), Integer.MIN_VALUE, entity.getY());
+            }
+
+            return true;
+        }
+
+        return super.update(source, tick);
+    }
+
+    @Override
+    public void toNBT(NbtCompound compound) {
+        super.toNBT(compound);
+        compound.putInt("suppressionCounter", suppressionCounter);
+    }
+
+    @Override
+    public void fromNBT(NbtCompound compound) {
+        super.fromNBT(compound);
+        suppressionCounter = compound.getInt("suppressionCounter");
+    }
+
+    @Override
+    public Optional<EntityAppearance> getAppearance() {
+        return isSuppressed() ? Optional.empty() : super.getAppearance();
+    }
+}
diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/DisguiseSpell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/DisguiseSpell.java
deleted file mode 100644
index 7b864297..00000000
--- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/DisguiseSpell.java
+++ /dev/null
@@ -1,232 +0,0 @@
-package com.minelittlepony.unicopia.ability.magic.spell;
-
-import java.util.Optional;
-
-import org.jetbrains.annotations.Nullable;
-
-import com.minelittlepony.unicopia.FlightType;
-import com.minelittlepony.unicopia.Owned;
-import com.minelittlepony.unicopia.ability.magic.Caster;
-import com.minelittlepony.unicopia.ability.magic.Suppressable;
-import com.minelittlepony.unicopia.ability.magic.spell.effect.AbstractSpell;
-import com.minelittlepony.unicopia.ability.magic.spell.effect.SpellType;
-import com.minelittlepony.unicopia.ability.magic.spell.trait.SpellTraits;
-import com.minelittlepony.unicopia.ability.magic.spell.trait.Trait;
-import com.minelittlepony.unicopia.entity.behaviour.EntityBehaviour;
-import com.minelittlepony.unicopia.entity.behaviour.Disguise;
-import com.minelittlepony.unicopia.entity.player.Pony;
-import com.minelittlepony.unicopia.entity.player.PlayerDimensions;
-import com.minelittlepony.unicopia.particle.MagicParticleEffect;
-import com.minelittlepony.unicopia.particle.UParticles;
-import com.minelittlepony.unicopia.projectile.ProjectileImpactListener;
-
-import net.minecraft.entity.Entity;
-import net.minecraft.entity.EntityDimensions;
-import net.minecraft.entity.LivingEntity;
-import net.minecraft.entity.data.TrackedData;
-import net.minecraft.entity.mob.MobEntity;
-import net.minecraft.entity.player.PlayerEntity;
-import net.minecraft.entity.projectile.ProjectileEntity;
-import net.minecraft.nbt.NbtCompound;
-
-/**
- * Shapeshifts the player.
- * <p>
- * Internal. Used by the changeling ability.
- */
-public class DisguiseSpell extends AbstractSpell implements Suppressable, FlightType.Provider, PlayerDimensions.Provider, ProjectileImpactListener {
-
-    private final Disguise disguise = new Disguise();
-
-    private int suppressionCounter;
-
-    public DisguiseSpell(SpellType<?> type, SpellTraits traits) {
-        super(type, traits);
-    }
-
-    @Override
-    public boolean isVulnerable(Caster<?> otherSource, Spell other) {
-        return suppressionCounter <= otherSource.getLevel().get();
-    }
-
-    @Override
-    public void onDestroyed(Caster<?> caster) {
-        caster.getEntity().calculateDimensions();
-        caster.getEntity().setInvisible(false);
-        if (caster instanceof Pony) {
-            ((Pony) caster).setInvisible(false);
-        }
-        disguise.remove();
-    }
-
-    @Override
-    public void onSuppressed(Caster<?> otherSource, float time) {
-        time /= getTraits().getOrDefault(Trait.STRENGTH, 1);
-        suppressionCounter = (int)(100 * time);
-        setDirty();
-    }
-
-    @Override
-    public boolean isSuppressed() {
-        return suppressionCounter > 0;
-    }
-
-    public Disguise getDisguise() {
-        return disguise;
-    }
-
-    public DisguiseSpell setDisguise(@Nullable Entity entity) {
-        if (entity == disguise.getAppearance()) {
-            entity = null;
-        }
-
-        disguise.setAppearance(entity);
-        setDirty();
-        return this;
-    }
-
-    @Override
-    public boolean onProjectileImpact(ProjectileEntity projectile) {
-        return disguise.getAppearance() == projectile;
-    }
-
-    @Override
-    public boolean tick(Caster<?> source, Situation situation) {
-        if (situation == Situation.BODY) {
-            return update(source, true);
-        }
-        return false;
-    }
-
-    @SuppressWarnings("unchecked")
-    public boolean update(Caster<?> source, boolean tick) {
-        if (source.isClient()) {
-            if (isSuppressed()) {
-                source.spawnParticles(MagicParticleEffect.UNICORN, 5);
-                source.spawnParticles(UParticles.CHANGELING_MAGIC, 5);
-            } else if (source.getWorld().random.nextInt(30) == 0) {
-                source.spawnParticles(UParticles.CHANGELING_MAGIC, 2);
-            }
-        }
-
-        LivingEntity owner = source.getMaster();
-
-        Entity entity = disguise.getAppearance();
-
-        if (isSuppressed()) {
-            suppressionCounter--;
-
-            owner.setInvisible(false);
-            if (source instanceof Pony) {
-                ((Pony)source).setInvisible(false);
-            }
-
-            if (entity != null) {
-                entity.setInvisible(true);
-                entity.setPos(entity.getX(), Integer.MIN_VALUE, entity.getY());
-            }
-
-            return true;
-        }
-
-        entity = disguise.getOrCreate(source);
-
-        if (owner == null) {
-            return true;
-        }
-
-        if (entity == null) {
-            owner.setInvisible(false);
-            if (source instanceof Pony) {
-                ((Pony) source).setInvisible(false);
-            }
-
-            owner.calculateDimensions();
-            return false;
-        }
-
-        entity.noClip = true;
-
-        if (entity instanceof MobEntity) {
-            ((MobEntity)entity).setAiDisabled(true);
-        }
-
-        entity.setInvisible(false);
-        entity.setNoGravity(true);
-
-        EntityBehaviour<Entity> behaviour = EntityBehaviour.forEntity(entity);
-
-        behaviour.copyBaseAttributes(owner, entity);
-
-        if (tick && !disguise.skipsUpdate()) {
-            entity.tick();
-        }
-
-        behaviour.update(source, entity, this);
-
-        if (source instanceof Pony) {
-            Pony player = (Pony)source;
-
-            source.getMaster().setInvisible(true);
-            player.setInvisible(true);
-
-            if (entity instanceof Owned) {
-                ((Owned<LivingEntity>)entity).setMaster(player.getMaster());
-            }
-
-            if (entity instanceof PlayerEntity) {
-                entity.getDataTracker().set(PlayerAccess.getModelBitFlag(), owner.getDataTracker().get(PlayerAccess.getModelBitFlag()));
-            }
-        }
-
-        return !isDead() && !source.getMaster().isDead();
-    }
-
-    @Override
-    public void setDead() {
-        super.setDead();
-        disguise.remove();
-    }
-
-    @Override
-    public void toNBT(NbtCompound compound) {
-        super.toNBT(compound);
-
-        compound.putInt("suppressionCounter", suppressionCounter);
-        disguise.toNBT(compound);
-    }
-
-    @Override
-    public void fromNBT(NbtCompound compound) {
-        super.fromNBT(compound);
-
-        suppressionCounter = compound.getInt("suppressionCounter");
-        disguise.fromNBT(compound);
-    }
-
-    @Override
-    public FlightType getFlightType() {
-        return getAppearance().map(Disguise::getFlightType).orElse(FlightType.UNSET);
-    }
-
-    public Optional<Disguise> getAppearance() {
-        return isSuppressed() ? Optional.empty() : Optional.ofNullable(disguise);
-    }
-
-    @Override
-    public Optional<Float> getTargetEyeHeight(Pony player) {
-        return getAppearance().flatMap(d -> d.getTargetEyeHeight(player));
-    }
-
-    @Override
-    public Optional<EntityDimensions> getTargetDimensions(Pony player) {
-        return getAppearance().flatMap(d -> d.getTargetDimensions(player));
-    }
-
-    static abstract class PlayerAccess extends PlayerEntity {
-        public PlayerAccess() { super(null, null, 0, null); }
-        static TrackedData<Byte> getModelBitFlag() {
-            return PLAYER_MODEL_PARTS;
-        }
-    }
-}
diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/SpellType.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/SpellType.java
index af750fb8..2b8c3bc2 100644
--- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/SpellType.java
+++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/SpellType.java
@@ -13,7 +13,8 @@ import com.minelittlepony.unicopia.ability.magic.Affine;
 import com.minelittlepony.unicopia.ability.magic.Caster;
 import com.minelittlepony.unicopia.ability.magic.SpellPredicate;
 import com.minelittlepony.unicopia.ability.magic.spell.CompoundSpell;
-import com.minelittlepony.unicopia.ability.magic.spell.DisguiseSpell;
+import com.minelittlepony.unicopia.ability.magic.spell.AbstractDisguiseSpell;
+import com.minelittlepony.unicopia.ability.magic.spell.ChangelingDisguiseSpell;
 import com.minelittlepony.unicopia.ability.magic.spell.JoustingSpell;
 import com.minelittlepony.unicopia.ability.magic.spell.PlaceableSpell;
 import com.minelittlepony.unicopia.ability.magic.spell.Spell;
@@ -40,7 +41,7 @@ public final class SpellType<T extends Spell> implements Affine, SpellPredicate<
     public static final SpellType<PlaceableSpell> PLACED_SPELL = register("placed", Affinity.NEUTRAL, 0, false, PlaceableSpell::new);
     public static final SpellType<ThrowableSpell> THROWN_SPELL = register("thrown", Affinity.NEUTRAL, 0, false, ThrowableSpell::new);
 
-    public static final SpellType<DisguiseSpell> DISGUISE = register("disguise", Affinity.BAD, 0x19E48E, false, DisguiseSpell::new);
+    public static final SpellType<AbstractDisguiseSpell> CHANGELING_DISGUISE = register("disguise", Affinity.BAD, 0x19E48E, false, ChangelingDisguiseSpell::new);
     public static final SpellType<JoustingSpell> RAINBOOM = register("rainboom", Affinity.GOOD, 0xBDBDF9, false, JoustingSpell::new);
 
     public static final SpellType<IceSpell> FROST = register("frost", Affinity.GOOD, 0xBDBDF9, true, IceSpell::new);
diff --git a/src/main/java/com/minelittlepony/unicopia/client/gui/UHud.java b/src/main/java/com/minelittlepony/unicopia/client/gui/UHud.java
index 8682d8fe..2de55c3a 100644
--- a/src/main/java/com/minelittlepony/unicopia/client/gui/UHud.java
+++ b/src/main/java/com/minelittlepony/unicopia/client/gui/UHud.java
@@ -9,11 +9,11 @@ import com.minelittlepony.unicopia.Race;
 import com.minelittlepony.unicopia.USounds;
 import com.minelittlepony.unicopia.ability.AbilityDispatcher;
 import com.minelittlepony.unicopia.ability.AbilitySlot;
-import com.minelittlepony.unicopia.ability.magic.spell.DisguiseSpell;
+import com.minelittlepony.unicopia.ability.magic.spell.AbstractDisguiseSpell;
 import com.minelittlepony.unicopia.ability.magic.spell.effect.SpellType;
 import com.minelittlepony.unicopia.client.KeyBindingsHandler;
 import com.minelittlepony.unicopia.client.sound.LoopingSoundInstance;
-import com.minelittlepony.unicopia.entity.behaviour.Disguise;
+import com.minelittlepony.unicopia.entity.behaviour.EntityAppearance;
 import com.minelittlepony.unicopia.entity.effect.SunBlindnessStatusEffect;
 import com.minelittlepony.unicopia.entity.effect.UEffects;
 import com.minelittlepony.unicopia.entity.player.Pony;
@@ -111,8 +111,8 @@ public class UHud extends DrawableHelper {
         matrices.pop();
 
         if (pony.getSpecies() == Race.CHANGELING && !client.player.isSneaking()) {
-            pony.getSpellSlot().get(SpellType.DISGUISE, false).map(DisguiseSpell::getDisguise)
-                .map(Disguise::getAppearance)
+            pony.getSpellSlot().get(SpellType.CHANGELING_DISGUISE, false).map(AbstractDisguiseSpell::getDisguise)
+                .map(EntityAppearance::getAppearance)
                 .ifPresent(appearance -> {
 
                     float baseHeight = 20;
diff --git a/src/main/java/com/minelittlepony/unicopia/client/render/WorldRenderDelegate.java b/src/main/java/com/minelittlepony/unicopia/client/render/WorldRenderDelegate.java
index bee52af5..80e78e96 100644
--- a/src/main/java/com/minelittlepony/unicopia/client/render/WorldRenderDelegate.java
+++ b/src/main/java/com/minelittlepony/unicopia/client/render/WorldRenderDelegate.java
@@ -3,11 +3,11 @@ package com.minelittlepony.unicopia.client.render;
 import org.jetbrains.annotations.Nullable;
 
 import com.minelittlepony.unicopia.ability.magic.Caster;
-import com.minelittlepony.unicopia.ability.magic.spell.effect.SpellType;
+import com.minelittlepony.unicopia.ability.magic.SpellPredicate;
 import com.minelittlepony.unicopia.entity.Equine;
 import com.minelittlepony.unicopia.entity.ItemImpl;
 import com.minelittlepony.unicopia.entity.Living;
-import com.minelittlepony.unicopia.entity.behaviour.Disguise;
+import com.minelittlepony.unicopia.entity.behaviour.EntityAppearance;
 import com.minelittlepony.unicopia.entity.behaviour.FallingBlockBehaviour;
 import com.minelittlepony.unicopia.entity.player.Pony;
 
@@ -93,10 +93,10 @@ public class WorldRenderDelegate {
 
             int fireTicks = pony.getMaster().doesRenderOnFire() ? 1 : 0;
 
-            return ((Caster<?>)pony).getSpellSlot().get(SpellType.DISGUISE, true).map(effect -> {
+            return ((Caster<?>)pony).getSpellSlot().get(SpellPredicate.IS_DISGUISE, true).map(effect -> {
                 effect.update(pony, false);
 
-                Disguise ve = effect.getDisguise();
+                EntityAppearance ve = effect.getDisguise();
                 Entity e = ve.getAppearance();
 
                 if (e != null) {
@@ -127,7 +127,7 @@ public class WorldRenderDelegate {
         }
     }
 
-    public void renderDisguise(EntityRenderDispatcher dispatcher, Disguise ve, Entity e,
+    public void renderDisguise(EntityRenderDispatcher dispatcher, EntityAppearance ve, Entity e,
             double x, double y, double z,
             int fireTicks, float tickDelta, MatrixStack matrices, VertexConsumerProvider vertexConsumers, int light) {
 
diff --git a/src/main/java/com/minelittlepony/unicopia/command/DisguiseCommand.java b/src/main/java/com/minelittlepony/unicopia/command/DisguiseCommand.java
index 0cbec6aa..135daf28 100644
--- a/src/main/java/com/minelittlepony/unicopia/command/DisguiseCommand.java
+++ b/src/main/java/com/minelittlepony/unicopia/command/DisguiseCommand.java
@@ -3,7 +3,7 @@ package com.minelittlepony.unicopia.command;
 import java.util.function.Function;
 
 import com.minelittlepony.unicopia.InteractionManager;
-import com.minelittlepony.unicopia.ability.magic.spell.Spell;
+import com.minelittlepony.unicopia.ability.magic.SpellPredicate;
 import com.minelittlepony.unicopia.ability.magic.spell.effect.SpellType;
 import com.minelittlepony.unicopia.ability.magic.spell.trait.SpellTraits;
 import com.minelittlepony.unicopia.entity.player.Pony;
@@ -83,8 +83,8 @@ public class DisguiseCommand {
         }
 
         Pony iplayer = Pony.of(player);
-        iplayer.getSpellSlot().get(SpellType.DISGUISE, true)
-            .orElseGet(() -> SpellType.DISGUISE.apply(iplayer, SpellTraits.EMPTY))
+        iplayer.getSpellSlot().get(SpellType.CHANGELING_DISGUISE, true)
+            .orElseGet(() -> SpellType.CHANGELING_DISGUISE.apply(iplayer, SpellTraits.EMPTY))
             .setDisguise(entity);
 
         if (source.getEntity() == player) {
@@ -112,7 +112,7 @@ public class DisguiseCommand {
 
     static int reveal(ServerCommandSource source, PlayerEntity player) {
         Pony iplayer = Pony.of(player);
-        iplayer.getSpellSlot().get(SpellType.DISGUISE, true).ifPresent(Spell::setDead);
+        iplayer.getSpellSlot().removeIf(SpellPredicate.IS_DISGUISE, true);
 
         if (source.getEntity() == player) {
             source.sendFeedback(new TranslatableText("commands.disguise.removed.self"), true);
diff --git a/src/main/java/com/minelittlepony/unicopia/entity/Living.java b/src/main/java/com/minelittlepony/unicopia/entity/Living.java
index a8278005..1453cabb 100644
--- a/src/main/java/com/minelittlepony/unicopia/entity/Living.java
+++ b/src/main/java/com/minelittlepony/unicopia/entity/Living.java
@@ -7,8 +7,8 @@ import org.jetbrains.annotations.Nullable;
 
 import com.minelittlepony.unicopia.ability.magic.Caster;
 import com.minelittlepony.unicopia.ability.magic.SpellContainer;
+import com.minelittlepony.unicopia.ability.magic.SpellPredicate;
 import com.minelittlepony.unicopia.ability.magic.spell.Situation;
-import com.minelittlepony.unicopia.ability.magic.spell.effect.SpellType;
 import com.minelittlepony.unicopia.item.UItems;
 import com.minelittlepony.unicopia.network.datasync.EffectSync;
 import com.minelittlepony.unicopia.projectile.ProjectileImpactListener;
@@ -161,7 +161,7 @@ public abstract class Living<T extends LivingEntity> implements Equine<T>, Caste
     }
 
     protected void handleFall(float distance, float damageMultiplier, DamageSource cause) {
-        getSpellSlot().get(SpellType.DISGUISE, false).ifPresent(spell -> {
+        getSpellSlot().get(SpellPredicate.IS_DISGUISE, false).ifPresent(spell -> {
             spell.getDisguise().onImpact(this, distance, damageMultiplier, cause);
         });
     }
diff --git a/src/main/java/com/minelittlepony/unicopia/entity/behaviour/AxolotlBehaviour.java b/src/main/java/com/minelittlepony/unicopia/entity/behaviour/AxolotlBehaviour.java
index 270a4312..2abe50a6 100644
--- a/src/main/java/com/minelittlepony/unicopia/entity/behaviour/AxolotlBehaviour.java
+++ b/src/main/java/com/minelittlepony/unicopia/entity/behaviour/AxolotlBehaviour.java
@@ -1,7 +1,6 @@
 package com.minelittlepony.unicopia.entity.behaviour;
 
 import com.minelittlepony.unicopia.ability.magic.Caster;
-import com.minelittlepony.unicopia.ability.magic.spell.DisguiseSpell;
 
 import net.minecraft.entity.passive.AxolotlEntity;
 import net.minecraft.util.math.Vec3f;
@@ -9,7 +8,7 @@ import net.minecraft.util.math.Vec3f;
 public class AxolotlBehaviour extends EntityBehaviour<AxolotlEntity> {
     private static final float toRad = 0.017453292F;
     @Override
-    public void update(Caster<?> source, AxolotlEntity entity, DisguiseSpell spell) {
+    public void update(Caster<?> source, AxolotlEntity entity, Disguise spell) {
         if (entity.getModelAngles().isEmpty()) {
             return;
         }
diff --git a/src/main/java/com/minelittlepony/unicopia/entity/behaviour/BeeBehaviour.java b/src/main/java/com/minelittlepony/unicopia/entity/behaviour/BeeBehaviour.java
index 880d9eb5..7d054758 100644
--- a/src/main/java/com/minelittlepony/unicopia/entity/behaviour/BeeBehaviour.java
+++ b/src/main/java/com/minelittlepony/unicopia/entity/behaviour/BeeBehaviour.java
@@ -2,13 +2,12 @@ package com.minelittlepony.unicopia.entity.behaviour;
 
 import com.minelittlepony.unicopia.InteractionManager;
 import com.minelittlepony.unicopia.ability.magic.Caster;
-import com.minelittlepony.unicopia.ability.magic.spell.DisguiseSpell;
 
 import net.minecraft.entity.passive.BeeEntity;
 
 public class BeeBehaviour extends EntityBehaviour<BeeEntity> {
     @Override
-    public BeeEntity onCreate(BeeEntity entity, Disguise context, boolean replaceOld) {
+    public BeeEntity onCreate(BeeEntity entity, EntityAppearance context, boolean replaceOld) {
         super.onCreate(entity, context, replaceOld);
         if (replaceOld && entity.world.isClient) {
             InteractionManager.instance().playLoopingSound(entity, InteractionManager.SOUND_BEE);
@@ -17,7 +16,7 @@ public class BeeBehaviour extends EntityBehaviour<BeeEntity> {
     }
 
     @Override
-    public void update(Caster<?> source, BeeEntity entity, DisguiseSpell spell) {
+    public void update(Caster<?> source, BeeEntity entity, Disguise spell) {
         if (source.getMaster().isSneaking()) {
             entity.setAngerTime(10);
         } else {
diff --git a/src/main/java/com/minelittlepony/unicopia/entity/behaviour/BlazeBehaviour.java b/src/main/java/com/minelittlepony/unicopia/entity/behaviour/BlazeBehaviour.java
index 76e5c296..95786ecf 100644
--- a/src/main/java/com/minelittlepony/unicopia/entity/behaviour/BlazeBehaviour.java
+++ b/src/main/java/com/minelittlepony/unicopia/entity/behaviour/BlazeBehaviour.java
@@ -1,7 +1,6 @@
 package com.minelittlepony.unicopia.entity.behaviour;
 
 import com.minelittlepony.unicopia.ability.magic.Caster;
-import com.minelittlepony.unicopia.ability.magic.spell.DisguiseSpell;
 import com.minelittlepony.unicopia.entity.player.Pony;
 import com.minelittlepony.unicopia.mixin.MixinBlazeEntity;
 
@@ -15,7 +14,7 @@ import net.minecraft.world.WorldEvents;
 
 public class BlazeBehaviour extends EntityBehaviour<BlazeEntity> {
     @Override
-    public void update(Caster<?> source, BlazeEntity entity, DisguiseSpell spell) {
+    public void update(Caster<?> source, BlazeEntity entity, Disguise spell) {
         super.update(source, entity, spell);
 
         Entity src = source.getEntity();
@@ -32,7 +31,7 @@ public class BlazeBehaviour extends EntityBehaviour<BlazeEntity> {
     }
 
     @Override
-    public void update(Pony player, BlazeEntity entity, DisguiseSpell spell) {
+    public void update(Pony player, BlazeEntity entity, Disguise spell) {
 
         NbtCompound tag = spell.getDisguise().getOrCreateTag();
 
diff --git a/src/main/java/com/minelittlepony/unicopia/entity/behaviour/ChickenBehaviour.java b/src/main/java/com/minelittlepony/unicopia/entity/behaviour/ChickenBehaviour.java
index f8962a87..f484b762 100644
--- a/src/main/java/com/minelittlepony/unicopia/entity/behaviour/ChickenBehaviour.java
+++ b/src/main/java/com/minelittlepony/unicopia/entity/behaviour/ChickenBehaviour.java
@@ -1,7 +1,6 @@
 package com.minelittlepony.unicopia.entity.behaviour;
 
 import com.minelittlepony.unicopia.ability.magic.Caster;
-import com.minelittlepony.unicopia.ability.magic.spell.DisguiseSpell;
 import com.minelittlepony.unicopia.entity.player.Pony;
 
 import net.minecraft.entity.Entity;
@@ -21,7 +20,7 @@ public class ChickenBehaviour extends EntityBehaviour<ChickenEntity> {
     }
 
     @Override
-    public void update(Caster<?> source, ChickenEntity entity, DisguiseSpell spell) {
+    public void update(Caster<?> source, ChickenEntity entity, Disguise spell) {
         entity.eggLayTime = Integer.MAX_VALUE;
 
         if (source instanceof Pony) {
diff --git a/src/main/java/com/minelittlepony/unicopia/entity/behaviour/CreeperBehaviour.java b/src/main/java/com/minelittlepony/unicopia/entity/behaviour/CreeperBehaviour.java
index df3793fd..5901b3bf 100644
--- a/src/main/java/com/minelittlepony/unicopia/entity/behaviour/CreeperBehaviour.java
+++ b/src/main/java/com/minelittlepony/unicopia/entity/behaviour/CreeperBehaviour.java
@@ -1,14 +1,13 @@
 package com.minelittlepony.unicopia.entity.behaviour;
 
 import com.minelittlepony.unicopia.ability.magic.Caster;
-import com.minelittlepony.unicopia.ability.magic.spell.DisguiseSpell;
 
 import net.minecraft.entity.mob.CreeperEntity;
 import net.minecraft.util.math.MathHelper;
 
 public class CreeperBehaviour extends EntityBehaviour<CreeperEntity> {
     @Override
-    public void update(Caster<?> source, CreeperEntity entity, DisguiseSpell spell) {
+    public void update(Caster<?> source, CreeperEntity entity, Disguise spell) {
         int fuseCountDown = spell.getDisguise().getOrCreateTag().getInt("fuseCountdown");
 
         boolean trigger = isSneakingOnGround(source);
diff --git a/src/main/java/com/minelittlepony/unicopia/entity/behaviour/Disguise.java b/src/main/java/com/minelittlepony/unicopia/entity/behaviour/Disguise.java
index 5808c5ab..d87686ac 100644
--- a/src/main/java/com/minelittlepony/unicopia/entity/behaviour/Disguise.java
+++ b/src/main/java/com/minelittlepony/unicopia/entity/behaviour/Disguise.java
@@ -1,399 +1,121 @@
 package com.minelittlepony.unicopia.entity.behaviour;
 
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Objects;
 import java.util.Optional;
-import java.util.UUID;
-import java.util.function.Consumer;
 
-import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 
 import com.minelittlepony.unicopia.FlightType;
-import com.minelittlepony.unicopia.InteractionManager;
 import com.minelittlepony.unicopia.Owned;
 import com.minelittlepony.unicopia.ability.magic.Caster;
-import com.minelittlepony.unicopia.ability.magic.spell.effect.SpellType;
-import com.minelittlepony.unicopia.entity.player.PlayerAttributes;
 import com.minelittlepony.unicopia.entity.player.PlayerDimensions;
 import com.minelittlepony.unicopia.entity.player.Pony;
-import com.minelittlepony.unicopia.projectile.ProjectileUtil;
-import com.minelittlepony.unicopia.util.NbtSerialisable;
-import com.mojang.authlib.GameProfile;
 
-import net.minecraft.block.ShapeContext;
-import net.minecraft.block.entity.BlockEntity;
-import net.minecraft.block.entity.SkullBlockEntity;
 import net.minecraft.entity.Entity;
 import net.minecraft.entity.EntityDimensions;
-import net.minecraft.entity.EntityType;
-import net.minecraft.entity.FallingBlockEntity;
-import net.minecraft.entity.Flutterer;
 import net.minecraft.entity.LivingEntity;
-import net.minecraft.entity.boss.dragon.EnderDragonEntity;
-import net.minecraft.entity.damage.DamageSource;
-import net.minecraft.entity.decoration.AbstractDecorationEntity;
-import net.minecraft.entity.mob.AmbientEntity;
-import net.minecraft.entity.mob.FlyingEntity;
-import net.minecraft.entity.mob.ShulkerEntity;
-import net.minecraft.entity.mob.SpiderEntity;
-import net.minecraft.entity.mob.VexEntity;
+import net.minecraft.entity.data.TrackedData;
+import net.minecraft.entity.mob.MobEntity;
 import net.minecraft.entity.player.PlayerEntity;
-import net.minecraft.entity.projectile.ShulkerBulletEntity;
-import net.minecraft.nbt.NbtCompound;
-import net.minecraft.util.function.BooleanBiFunction;
-import net.minecraft.util.math.BlockPos;
-import net.minecraft.util.math.Box;
-import net.minecraft.util.shape.VoxelShape;
-import net.minecraft.util.shape.VoxelShapes;
-import net.minecraft.world.WorldAccess;
 
-public class Disguise implements NbtSerialisable, PlayerDimensions.Provider, FlightType.Provider {
-    private static final Optional<Float> BLOCK_HEIGHT = Optional.of(0.5F);
+public interface Disguise extends FlightType.Provider, PlayerDimensions.Provider {
 
-    @NotNull
-    private String entityId = "";
+    EntityAppearance getDisguise();
 
-    @Nullable
-    private Entity entity;
+    void setDirty();
 
-    @Nullable
-    private BlockEntity blockEntity;
+    boolean isDead();
 
-    private List<Entity> attachments = new ArrayList<>();
-
-    private Optional<EntityDimensions> dimensions = Optional.empty();
-
-    /**
-     * Tag that allows behaviours to store data between ticks.
-     * This is not serialized, so should only be used for server-side data.
-     */
-    @Nullable
-    private NbtCompound tag;
-
-    @Nullable
-    private NbtCompound entityNbt;
-
-    @Nullable
-    public Entity getAppearance() {
-        return entity;
+    default Optional<EntityAppearance> getAppearance() {
+        return Optional.ofNullable(getDisguise());
     }
 
-    @Nullable
-    public BlockEntity getBlockEntity() {
-        return blockEntity;
+    @Override
+    default FlightType getFlightType() {
+        return getAppearance().map(EntityAppearance::getFlightType).orElse(FlightType.UNSET);
     }
 
-    public List<Entity> getAttachments() {
-        return attachments;
+    @Override
+    default Optional<Float> getTargetEyeHeight(Pony player) {
+        return getAppearance().flatMap(d -> d.getTargetEyeHeight(player));
     }
 
-    public void addBlockEntity(BlockEntity blockEntity) {
-        this.blockEntity = blockEntity;
+    @Override
+    default Optional<EntityDimensions> getTargetDimensions(Pony player) {
+        return getAppearance().flatMap(d -> d.getTargetDimensions(player));
     }
 
-    public void attachExtraEntity(Entity entity) {
-        attachments.add(entity);
-    }
-
-    public void setAppearance(@Nullable Entity entity) {
-        remove();
-
-        entityNbt = entity == null ? null : encodeEntityToNBT(entity);
-        entityId = entityNbt == null ? "" : entityNbt.getString("id");
-    }
-
-    public boolean isPresent() {
-        return entity != null;
-    }
-
-    public NbtCompound getOrCreateTag() {
-        if (tag == null) {
-            tag = new NbtCompound();
-        }
-        return tag;
-    }
-
-    public boolean hasTag() {
-        return tag != null;
-    }
-
-    public void remove() {
-        attachments.clear();
-        if (entity != null) {
-            EntityBehaviour.forEntity(entity).onDestroy(entity);
+    default Disguise setDisguise(@Nullable Entity entity) {
+        if (entity == getDisguise().getAppearance()) {
             entity = null;
         }
-        if (blockEntity != null) {
-            blockEntity.markRemoved();
-            blockEntity = null;
-        }
+
+        getDisguise().setAppearance(entity);
+        setDirty();
+        return this;
     }
 
-    private synchronized void createPlayer(NbtCompound nbt, GameProfile profile, Caster<?> source) {
-        remove();
+    @SuppressWarnings("unchecked")
+    default boolean update(Caster<?> source, boolean tick) {
 
-        entity = InteractionManager.instance().createPlayer(source.getEntity(), profile);
-        entity.setCustomName(source.getMaster().getName());
-        ((PlayerEntity)entity).readNbt(nbt.getCompound("playerNbt"));
-        entity.setUuid(UUID.randomUUID());
-        entity.extinguish();
+        LivingEntity owner = source.getMaster();
 
-        onEntityLoaded(source);
-    }
+        Entity entity = getDisguise().getOrCreate(source);
 
-    public Entity getOrCreate(Caster<?> source) {
-        if (entity == null && entityNbt != null) {
-            NbtCompound nbt = entityNbt;
-            entity = null;
-            entityNbt = null;
-            attachments.clear();
-
-            if ("player".equals(entityId)) {
-                createPlayer(nbt, new GameProfile(
-                        nbt.containsUuid("playerId") ? nbt.getUuid("playerId") : UUID.randomUUID(),
-                                nbt.getString("playerName")
-                            ), source);
-
-                SkullBlockEntity.loadProperties(new GameProfile(
-                        nbt.containsUuid("playerId") ? nbt.getUuid("playerId") : null,
-                                nbt.getString("playerName")
-                            ), p -> createPlayer(nbt, p, source));
-            } else {
-                if (source.isClient()) {
-                    entity = EntityType.fromNbt(nbt).map(type -> type.create(source.getWorld())).orElse(null);
-                    if (entity != null) {
-                        try {
-                            entity.readNbt(nbt);
-                        } catch (Exception ignored) {
-                            // Mojang pls
-                        }
-                        entity = EntityBehaviour.forEntity(entity).onCreate(entity, this, true);
-                    }
-                } else {
-                    entity = EntityType.loadEntityWithPassengers(nbt, source.getWorld(), e -> {
-                        return EntityBehaviour.forEntity(e).onCreate(e, this, true);
-                    });
-                }
-
-                onEntityLoaded(source);
-            }
-        }
-
-        return entity;
-    }
-
-    public void onImpact(Caster<?> pony, float distance, float damageMultiplier, DamageSource cause) {
-        EntityBehaviour.forEntity(entity).onImpact(pony, entity, distance, damageMultiplier, cause);
-    }
-
-    private void onEntityLoaded(Caster<?> source) {
-        source.getEntity().calculateDimensions();
-
-        if (entity == null) {
-            return;
-        }
-
-        Caster.of(entity).ifPresent(c -> c.getSpellSlot().clear());
-
-        if (entity instanceof LivingEntity) {
-            ((LivingEntity) entity).getAttributeInstance(PlayerAttributes.ENTITY_GRAVTY_MODIFIER).clearModifiers();
-        }
-
-        if (source.isClient()) {
-            source.getWorld().spawnEntity(entity);
-        }
-    }
-
-    @Override
-    public FlightType getFlightType() {
-        if (!isPresent()) {
-            return FlightType.UNSET;
+        if (owner == null) {
+            return true;
         }
 
         if (entity == null) {
-            return FlightType.NONE;
-        }
-
-        if (entity instanceof Owned) {
-            @SuppressWarnings("unchecked")
-            Pony iplayer = Pony.of(((Owned<PlayerEntity>)entity).getMaster());
-
-            return iplayer == null ? FlightType.NONE : iplayer.getSpecies().getFlightType();
-        }
-
-        if (entity instanceof FlyingEntity
-                || entity instanceof AmbientEntity
-                || entity instanceof EnderDragonEntity
-                || entity instanceof VexEntity
-                || entity instanceof ShulkerBulletEntity
-                || entity instanceof Flutterer
-                || ProjectileUtil.isFlyingProjectile(entity)) {
-            return FlightType.INSECTOID;
-        }
-
-        return FlightType.NONE;
-    }
-
-    @Override
-    public Optional<Float> getTargetEyeHeight(Pony player) {
-        if (entity != null) {
-            if (entity instanceof FallingBlockEntity) {
-                return BLOCK_HEIGHT;
+            owner.setInvisible(false);
+            if (source instanceof Pony) {
+                ((Pony) source).setInvisible(false);
             }
-            return Optional.of(entity.getStandingEyeHeight());
-        }
-        return Optional.empty();
-    }
 
-    public float getHeight() {
-        if (entity != null) {
-            if (entity instanceof FallingBlockEntity) {
-                return 0.9F;
-            }
-            return entity.getHeight() - 0.1F;
-        }
-        return -1;
-    }
-
-    public Optional<Double> getDistance(Pony player) {
-        return EntityBehaviour.forEntity(entity).getCameraDistance(entity, player);
-    }
-
-    @Override
-    public Optional<EntityDimensions> getTargetDimensions(Pony player) {
-        return dimensions = EntityBehaviour.forEntity(entity).getDimensions(entity, dimensions);
-    }
-
-    public boolean skipsUpdate() {
-        return entity instanceof FallingBlockEntity
-            || entity instanceof AbstractDecorationEntity
-            || entity instanceof PlayerEntity;
-    }
-
-    public boolean isAxisAligned() {
-        return isAxisAligned(entity);
-    }
-
-    public boolean canClimbWalls() {
-        return entity instanceof SpiderEntity;
-    }
-
-    @Override
-    public void toNBT(NbtCompound compound) {
-        compound.putString("entityId", entityId);
-
-        if (entityNbt != null) {
-            compound.put("entity", entityNbt);
-        } else if (entity != null) {
-            compound.put("entity", encodeEntityToNBT(entity));
-        }
-    }
-
-    @Override
-    public void fromNBT(NbtCompound compound) {
-        String newId = compound.getString("entityId");
-
-        String newPlayerName = null;
-        if (compound.contains("entity") && compound.getCompound("entity").contains("playerName")) {
-            newPlayerName = compound.getCompound("entity").getString("playerName");
-        }
-
-        String oldPlayerName = entity != null && entity instanceof PlayerEntity ? ((PlayerEntity)entity).getGameProfile().getName() : null;
-
-        if (!Objects.equals(newId, entityId) || !Objects.equals(newPlayerName, oldPlayerName)) {
-            entityNbt = null;
-            remove();
-        }
-
-        if (compound.contains("entity")) {
-            entityId = newId;
-
-            entityNbt = compound.getCompound("entity");
-
-            compound.getString("entityData");
-
-            if (entity != null) {
-                try {
-                    entity.readNbt(entityNbt);
-                } catch (Exception ignored) {
-                    // Mojang pls
-                }
-
-                attachments.clear();
-                entity = EntityBehaviour.forEntity(entity).onCreate(entity, this, false);
-            }
-        }
-    }
-
-    public static boolean isAxisAligned(@Nullable Entity entity) {
-        return entity instanceof ShulkerEntity
-            || entity instanceof AbstractDecorationEntity
-            || entity instanceof FallingBlockEntity;
-    }
-
-    private static NbtCompound encodeEntityToNBT(Entity entity) {
-        NbtCompound entityNbt = new NbtCompound();
-
-        if (entity instanceof PlayerEntity) {
-            GameProfile profile = ((PlayerEntity)entity).getGameProfile();
-
-            entityNbt.putString("id", "player");
-            if (profile.getId() != null) {
-                entityNbt.putUuid("playerId", profile.getId());
-            }
-            entityNbt.putString("playerName", profile.getName());
-
-            NbtCompound tag = new NbtCompound();
-
-            entity.writeNbt(tag);
-
-            entityNbt.put("playerNbt", tag);
-        } else {
-            entity.saveSelfNbt(entityNbt);
-        }
-
-        return entityNbt;
-    }
-
-    void getCollissionShapes(ShapeContext context, Consumer<VoxelShape> output) {
-        getCollissionShapes(getAppearance(), context, output);
-        getAttachments().forEach(e -> getCollissionShapes(e, context, output));
-    }
-
-    private static void getCollissionShapes(@Nullable Entity entity, ShapeContext context, Consumer<VoxelShape> output) {
-        if (entity == null) {
-            return;
-        }
-
-        if (entity.isCollidable()) {
-            output.accept(VoxelShapes.cuboid(entity.getBoundingBox()));
-        } else if (entity instanceof FallingBlockEntity) {
-            BlockPos pos = entity.getBlockPos();
-            output.accept(((FallingBlockEntity) entity).getBlockState()
-                    .getCollisionShape(entity.world, entity.getBlockPos(), context)
-                    .offset(pos.getX(), pos.getY(), pos.getZ())
-            );
-        }
-    }
-
-    public static List<VoxelShape> getColissonShapes(@Nullable Entity entity, WorldAccess world, Box box) {
-        List<VoxelShape> shapes = new ArrayList<>();
-        ShapeContext ctx = entity == null ? ShapeContext.absent() : ShapeContext.of(entity);
-        VoxelShape entityShape = VoxelShapes.cuboid(box.expand(1.0E-6D));
-
-        world.getOtherEntities(entity, box.expand(0.5), e -> {
-            Caster.of(e).flatMap(c -> c.getSpellSlot().get(SpellType.DISGUISE, false)).ifPresent(p -> {
-                p.getDisguise().getCollissionShapes(ctx, shape -> {
-                    if (!shape.isEmpty() && VoxelShapes.matchesAnywhere(shape, entityShape, BooleanBiFunction.AND)) {
-                        shapes.add(shape);
-                    }
-                });
-            });
+            owner.calculateDimensions();
             return false;
-        });
+        }
 
-        return shapes;
+        entity.noClip = true;
+
+        if (entity instanceof MobEntity) {
+            ((MobEntity)entity).setAiDisabled(true);
+        }
+
+        entity.setInvisible(false);
+        entity.setNoGravity(true);
+
+        EntityBehaviour<Entity> behaviour = EntityBehaviour.forEntity(entity);
+
+        behaviour.copyBaseAttributes(owner, entity);
+
+        if (tick && !getDisguise().skipsUpdate()) {
+            entity.tick();
+        }
+
+        behaviour.update(source, entity, this);
+
+        if (source instanceof Pony) {
+            Pony player = (Pony)source;
+
+            source.getMaster().setInvisible(true);
+            player.setInvisible(true);
+
+            if (entity instanceof Owned) {
+                ((Owned<LivingEntity>)entity).setMaster(player.getMaster());
+            }
+
+            if (entity instanceof PlayerEntity) {
+                entity.getDataTracker().set(PlayerAccess.getModelBitFlag(), owner.getDataTracker().get(PlayerAccess.getModelBitFlag()));
+            }
+        }
+
+        return !isDead() && !source.getMaster().isDead();
+    }
+
+    static abstract class PlayerAccess extends PlayerEntity {
+        public PlayerAccess() { super(null, null, 0, null); }
+        static TrackedData<Byte> getModelBitFlag() {
+            return PLAYER_MODEL_PARTS;
+        }
     }
 }
diff --git a/src/main/java/com/minelittlepony/unicopia/entity/behaviour/EndermanBehaviour.java b/src/main/java/com/minelittlepony/unicopia/entity/behaviour/EndermanBehaviour.java
index 0b7d6786..159bf793 100644
--- a/src/main/java/com/minelittlepony/unicopia/entity/behaviour/EndermanBehaviour.java
+++ b/src/main/java/com/minelittlepony/unicopia/entity/behaviour/EndermanBehaviour.java
@@ -1,7 +1,6 @@
 package com.minelittlepony.unicopia.entity.behaviour;
 
 import com.minelittlepony.unicopia.ability.magic.Caster;
-import com.minelittlepony.unicopia.ability.magic.spell.DisguiseSpell;
 
 import net.minecraft.entity.mob.EndermanEntity;
 import net.minecraft.item.BlockItem;
@@ -10,7 +9,7 @@ import net.minecraft.util.Hand;
 
 public class EndermanBehaviour extends EntityBehaviour<EndermanEntity> {
     @Override
-    public void update(Caster<?> source, EndermanEntity entity, DisguiseSpell spell) {
+    public void update(Caster<?> source, EndermanEntity entity, Disguise spell) {
         if (source.getMaster().isSneaking() || source.getMaster().isSprinting()) {
             entity.setTarget(entity);
         } else {
diff --git a/src/main/java/com/minelittlepony/unicopia/entity/behaviour/EntityAppearance.java b/src/main/java/com/minelittlepony/unicopia/entity/behaviour/EntityAppearance.java
new file mode 100644
index 00000000..edee5a6d
--- /dev/null
+++ b/src/main/java/com/minelittlepony/unicopia/entity/behaviour/EntityAppearance.java
@@ -0,0 +1,399 @@
+package com.minelittlepony.unicopia.entity.behaviour;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.UUID;
+import java.util.function.Consumer;
+
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import com.minelittlepony.unicopia.FlightType;
+import com.minelittlepony.unicopia.InteractionManager;
+import com.minelittlepony.unicopia.Owned;
+import com.minelittlepony.unicopia.ability.magic.Caster;
+import com.minelittlepony.unicopia.ability.magic.SpellPredicate;
+import com.minelittlepony.unicopia.entity.player.PlayerAttributes;
+import com.minelittlepony.unicopia.entity.player.PlayerDimensions;
+import com.minelittlepony.unicopia.entity.player.Pony;
+import com.minelittlepony.unicopia.projectile.ProjectileUtil;
+import com.minelittlepony.unicopia.util.NbtSerialisable;
+import com.mojang.authlib.GameProfile;
+
+import net.minecraft.block.ShapeContext;
+import net.minecraft.block.entity.BlockEntity;
+import net.minecraft.block.entity.SkullBlockEntity;
+import net.minecraft.entity.Entity;
+import net.minecraft.entity.EntityDimensions;
+import net.minecraft.entity.EntityType;
+import net.minecraft.entity.FallingBlockEntity;
+import net.minecraft.entity.Flutterer;
+import net.minecraft.entity.LivingEntity;
+import net.minecraft.entity.boss.dragon.EnderDragonEntity;
+import net.minecraft.entity.damage.DamageSource;
+import net.minecraft.entity.decoration.AbstractDecorationEntity;
+import net.minecraft.entity.mob.AmbientEntity;
+import net.minecraft.entity.mob.FlyingEntity;
+import net.minecraft.entity.mob.ShulkerEntity;
+import net.minecraft.entity.mob.SpiderEntity;
+import net.minecraft.entity.mob.VexEntity;
+import net.minecraft.entity.player.PlayerEntity;
+import net.minecraft.entity.projectile.ShulkerBulletEntity;
+import net.minecraft.nbt.NbtCompound;
+import net.minecraft.util.function.BooleanBiFunction;
+import net.minecraft.util.math.BlockPos;
+import net.minecraft.util.math.Box;
+import net.minecraft.util.shape.VoxelShape;
+import net.minecraft.util.shape.VoxelShapes;
+import net.minecraft.world.WorldAccess;
+
+public class EntityAppearance implements NbtSerialisable, PlayerDimensions.Provider, FlightType.Provider {
+    private static final Optional<Float> BLOCK_HEIGHT = Optional.of(0.5F);
+
+    @NotNull
+    private String entityId = "";
+
+    @Nullable
+    private Entity entity;
+
+    @Nullable
+    private BlockEntity blockEntity;
+
+    private List<Entity> attachments = new ArrayList<>();
+
+    private Optional<EntityDimensions> dimensions = Optional.empty();
+
+    /**
+     * Tag that allows behaviours to store data between ticks.
+     * This is not serialized, so should only be used for server-side data.
+     */
+    @Nullable
+    private NbtCompound tag;
+
+    @Nullable
+    private NbtCompound entityNbt;
+
+    @Nullable
+    public Entity getAppearance() {
+        return entity;
+    }
+
+    @Nullable
+    public BlockEntity getBlockEntity() {
+        return blockEntity;
+    }
+
+    public List<Entity> getAttachments() {
+        return attachments;
+    }
+
+    public void addBlockEntity(BlockEntity blockEntity) {
+        this.blockEntity = blockEntity;
+    }
+
+    public void attachExtraEntity(Entity entity) {
+        attachments.add(entity);
+    }
+
+    public void setAppearance(@Nullable Entity entity) {
+        remove();
+
+        entityNbt = entity == null ? null : encodeEntityToNBT(entity);
+        entityId = entityNbt == null ? "" : entityNbt.getString("id");
+    }
+
+    public boolean isPresent() {
+        return entity != null;
+    }
+
+    public NbtCompound getOrCreateTag() {
+        if (tag == null) {
+            tag = new NbtCompound();
+        }
+        return tag;
+    }
+
+    public boolean hasTag() {
+        return tag != null;
+    }
+
+    public void remove() {
+        attachments.clear();
+        if (entity != null) {
+            EntityBehaviour.forEntity(entity).onDestroy(entity);
+            entity = null;
+        }
+        if (blockEntity != null) {
+            blockEntity.markRemoved();
+            blockEntity = null;
+        }
+    }
+
+    private synchronized void createPlayer(NbtCompound nbt, GameProfile profile, Caster<?> source) {
+        remove();
+
+        entity = InteractionManager.instance().createPlayer(source.getEntity(), profile);
+        entity.setCustomName(source.getMaster().getName());
+        ((PlayerEntity)entity).readNbt(nbt.getCompound("playerNbt"));
+        entity.setUuid(UUID.randomUUID());
+        entity.extinguish();
+
+        onEntityLoaded(source);
+    }
+
+    public Entity getOrCreate(Caster<?> source) {
+        if (entity == null && entityNbt != null) {
+            NbtCompound nbt = entityNbt;
+            entity = null;
+            entityNbt = null;
+            attachments.clear();
+
+            if ("player".equals(entityId)) {
+                createPlayer(nbt, new GameProfile(
+                        nbt.containsUuid("playerId") ? nbt.getUuid("playerId") : UUID.randomUUID(),
+                                nbt.getString("playerName")
+                            ), source);
+
+                SkullBlockEntity.loadProperties(new GameProfile(
+                        nbt.containsUuid("playerId") ? nbt.getUuid("playerId") : null,
+                                nbt.getString("playerName")
+                            ), p -> createPlayer(nbt, p, source));
+            } else {
+                if (source.isClient()) {
+                    entity = EntityType.fromNbt(nbt).map(type -> type.create(source.getWorld())).orElse(null);
+                    if (entity != null) {
+                        try {
+                            entity.readNbt(nbt);
+                        } catch (Exception ignored) {
+                            // Mojang pls
+                        }
+                        entity = EntityBehaviour.forEntity(entity).onCreate(entity, this, true);
+                    }
+                } else {
+                    entity = EntityType.loadEntityWithPassengers(nbt, source.getWorld(), e -> {
+                        return EntityBehaviour.forEntity(e).onCreate(e, this, true);
+                    });
+                }
+
+                onEntityLoaded(source);
+            }
+        }
+
+        return entity;
+    }
+
+    public void onImpact(Caster<?> pony, float distance, float damageMultiplier, DamageSource cause) {
+        EntityBehaviour.forEntity(entity).onImpact(pony, entity, distance, damageMultiplier, cause);
+    }
+
+    private void onEntityLoaded(Caster<?> source) {
+        source.getEntity().calculateDimensions();
+
+        if (entity == null) {
+            return;
+        }
+
+        Caster.of(entity).ifPresent(c -> c.getSpellSlot().clear());
+
+        if (entity instanceof LivingEntity) {
+            ((LivingEntity) entity).getAttributeInstance(PlayerAttributes.ENTITY_GRAVTY_MODIFIER).clearModifiers();
+        }
+
+        if (source.isClient()) {
+            source.getWorld().spawnEntity(entity);
+        }
+    }
+
+    @Override
+    public FlightType getFlightType() {
+        if (!isPresent()) {
+            return FlightType.UNSET;
+        }
+
+        if (entity == null) {
+            return FlightType.NONE;
+        }
+
+        if (entity instanceof Owned) {
+            @SuppressWarnings("unchecked")
+            Pony iplayer = Pony.of(((Owned<PlayerEntity>)entity).getMaster());
+
+            return iplayer == null ? FlightType.NONE : iplayer.getSpecies().getFlightType();
+        }
+
+        if (entity instanceof FlyingEntity
+                || entity instanceof AmbientEntity
+                || entity instanceof EnderDragonEntity
+                || entity instanceof VexEntity
+                || entity instanceof ShulkerBulletEntity
+                || entity instanceof Flutterer
+                || ProjectileUtil.isFlyingProjectile(entity)) {
+            return FlightType.INSECTOID;
+        }
+
+        return FlightType.NONE;
+    }
+
+    @Override
+    public Optional<Float> getTargetEyeHeight(Pony player) {
+        if (entity != null) {
+            if (entity instanceof FallingBlockEntity) {
+                return BLOCK_HEIGHT;
+            }
+            return Optional.of(entity.getStandingEyeHeight());
+        }
+        return Optional.empty();
+    }
+
+    public float getHeight() {
+        if (entity != null) {
+            if (entity instanceof FallingBlockEntity) {
+                return 0.9F;
+            }
+            return entity.getHeight() - 0.1F;
+        }
+        return -1;
+    }
+
+    public Optional<Double> getDistance(Pony player) {
+        return EntityBehaviour.forEntity(entity).getCameraDistance(entity, player);
+    }
+
+    @Override
+    public Optional<EntityDimensions> getTargetDimensions(Pony player) {
+        return dimensions = EntityBehaviour.forEntity(entity).getDimensions(entity, dimensions);
+    }
+
+    public boolean skipsUpdate() {
+        return entity instanceof FallingBlockEntity
+            || entity instanceof AbstractDecorationEntity
+            || entity instanceof PlayerEntity;
+    }
+
+    public boolean isAxisAligned() {
+        return isAxisAligned(entity);
+    }
+
+    public boolean canClimbWalls() {
+        return entity instanceof SpiderEntity;
+    }
+
+    @Override
+    public void toNBT(NbtCompound compound) {
+        compound.putString("entityId", entityId);
+
+        if (entityNbt != null) {
+            compound.put("entity", entityNbt);
+        } else if (entity != null) {
+            compound.put("entity", encodeEntityToNBT(entity));
+        }
+    }
+
+    @Override
+    public void fromNBT(NbtCompound compound) {
+        String newId = compound.getString("entityId");
+
+        String newPlayerName = null;
+        if (compound.contains("entity") && compound.getCompound("entity").contains("playerName")) {
+            newPlayerName = compound.getCompound("entity").getString("playerName");
+        }
+
+        String oldPlayerName = entity != null && entity instanceof PlayerEntity ? ((PlayerEntity)entity).getGameProfile().getName() : null;
+
+        if (!Objects.equals(newId, entityId) || !Objects.equals(newPlayerName, oldPlayerName)) {
+            entityNbt = null;
+            remove();
+        }
+
+        if (compound.contains("entity")) {
+            entityId = newId;
+
+            entityNbt = compound.getCompound("entity");
+
+            compound.getString("entityData");
+
+            if (entity != null) {
+                try {
+                    entity.readNbt(entityNbt);
+                } catch (Exception ignored) {
+                    // Mojang pls
+                }
+
+                attachments.clear();
+                entity = EntityBehaviour.forEntity(entity).onCreate(entity, this, false);
+            }
+        }
+    }
+
+    public static boolean isAxisAligned(@Nullable Entity entity) {
+        return entity instanceof ShulkerEntity
+            || entity instanceof AbstractDecorationEntity
+            || entity instanceof FallingBlockEntity;
+    }
+
+    private static NbtCompound encodeEntityToNBT(Entity entity) {
+        NbtCompound entityNbt = new NbtCompound();
+
+        if (entity instanceof PlayerEntity) {
+            GameProfile profile = ((PlayerEntity)entity).getGameProfile();
+
+            entityNbt.putString("id", "player");
+            if (profile.getId() != null) {
+                entityNbt.putUuid("playerId", profile.getId());
+            }
+            entityNbt.putString("playerName", profile.getName());
+
+            NbtCompound tag = new NbtCompound();
+
+            entity.writeNbt(tag);
+
+            entityNbt.put("playerNbt", tag);
+        } else {
+            entity.saveSelfNbt(entityNbt);
+        }
+
+        return entityNbt;
+    }
+
+    void getCollissionShapes(ShapeContext context, Consumer<VoxelShape> output) {
+        getCollissionShapes(getAppearance(), context, output);
+        getAttachments().forEach(e -> getCollissionShapes(e, context, output));
+    }
+
+    private static void getCollissionShapes(@Nullable Entity entity, ShapeContext context, Consumer<VoxelShape> output) {
+        if (entity == null) {
+            return;
+        }
+
+        if (entity.isCollidable()) {
+            output.accept(VoxelShapes.cuboid(entity.getBoundingBox()));
+        } else if (entity instanceof FallingBlockEntity) {
+            BlockPos pos = entity.getBlockPos();
+            output.accept(((FallingBlockEntity) entity).getBlockState()
+                    .getCollisionShape(entity.world, entity.getBlockPos(), context)
+                    .offset(pos.getX(), pos.getY(), pos.getZ())
+            );
+        }
+    }
+
+    public static List<VoxelShape> getColissonShapes(@Nullable Entity entity, WorldAccess world, Box box) {
+        List<VoxelShape> shapes = new ArrayList<>();
+        ShapeContext ctx = entity == null ? ShapeContext.absent() : ShapeContext.of(entity);
+        VoxelShape entityShape = VoxelShapes.cuboid(box.expand(1.0E-6D));
+
+        world.getOtherEntities(entity, box.expand(0.5), e -> {
+            Caster.of(e).flatMap(c -> c.getSpellSlot().get(SpellPredicate.IS_DISGUISE, false)).ifPresent(p -> {
+                p.getDisguise().getCollissionShapes(ctx, shape -> {
+                    if (!shape.isEmpty() && VoxelShapes.matchesAnywhere(shape, entityShape, BooleanBiFunction.AND)) {
+                        shapes.add(shape);
+                    }
+                });
+            });
+            return false;
+        });
+
+        return shapes;
+    }
+}
diff --git a/src/main/java/com/minelittlepony/unicopia/entity/behaviour/EntityBehaviour.java b/src/main/java/com/minelittlepony/unicopia/entity/behaviour/EntityBehaviour.java
index 3536bc5e..834577a7 100644
--- a/src/main/java/com/minelittlepony/unicopia/entity/behaviour/EntityBehaviour.java
+++ b/src/main/java/com/minelittlepony/unicopia/entity/behaviour/EntityBehaviour.java
@@ -6,7 +6,6 @@ import java.util.function.Supplier;
 import org.jetbrains.annotations.Nullable;
 
 import com.minelittlepony.unicopia.ability.magic.Caster;
-import com.minelittlepony.unicopia.ability.magic.spell.DisguiseSpell;
 import com.minelittlepony.unicopia.entity.ItemWielder;
 import com.minelittlepony.unicopia.entity.player.Pony;
 import com.minelittlepony.unicopia.mixin.MixinEntity;
@@ -45,13 +44,13 @@ public class EntityBehaviour<T extends Entity> {
      * <br>
      * We use this to add entity-specific behaviours.
      */
-    public void update(Caster<?> source, T entity, DisguiseSpell spell) {
+    public void update(Caster<?> source, T entity, Disguise spell) {
         if (source instanceof Pony) {
             update((Pony)source, entity, spell);
         }
     }
 
-    protected void update(Pony pony, T entity, DisguiseSpell spell) {
+    protected void update(Pony pony, T entity, Disguise spell) {
 
     }
 
@@ -59,7 +58,7 @@ public class EntityBehaviour<T extends Entity> {
 
     }
 
-    public T onCreate(T entity, Disguise context, boolean wasNew) {
+    public T onCreate(T entity, EntityAppearance context, boolean wasNew) {
         entity.extinguish();
         return entity;
     }
@@ -120,7 +119,7 @@ public class EntityBehaviour<T extends Entity> {
             to.horizontalCollision = from.horizontalCollision;
         }
 
-        if (Disguise.isAxisAligned(to)) {
+        if (EntityAppearance.isAxisAligned(to)) {
             double x = positionOffset.x + Math.floor(from.getX()) + 0.5;
             double y = positionOffset.y + Math.floor(from.getY());
             double z = positionOffset.z + Math.floor(from.getZ()) + 0.5;
diff --git a/src/main/java/com/minelittlepony/unicopia/entity/behaviour/FallingBlockBehaviour.java b/src/main/java/com/minelittlepony/unicopia/entity/behaviour/FallingBlockBehaviour.java
index 0246c7b3..ba396c80 100644
--- a/src/main/java/com/minelittlepony/unicopia/entity/behaviour/FallingBlockBehaviour.java
+++ b/src/main/java/com/minelittlepony/unicopia/entity/behaviour/FallingBlockBehaviour.java
@@ -4,7 +4,6 @@ import java.util.List;
 import java.util.Optional;
 
 import com.minelittlepony.unicopia.ability.magic.Caster;
-import com.minelittlepony.unicopia.ability.magic.spell.DisguiseSpell;
 import com.minelittlepony.unicopia.entity.player.Pony;
 import com.minelittlepony.unicopia.mixin.MixinFallingBlock;
 import com.minelittlepony.unicopia.util.Tickable;
@@ -62,7 +61,7 @@ public class FallingBlockBehaviour extends EntityBehaviour<FallingBlockEntity> {
     }
 
     @Override
-    public FallingBlockEntity onCreate(FallingBlockEntity entity, Disguise context, boolean replaceOld) {
+    public FallingBlockEntity onCreate(FallingBlockEntity entity, EntityAppearance context, boolean replaceOld) {
         super.onCreate(entity, context, replaceOld);
 
         BlockState state = entity.getBlockState();
@@ -85,7 +84,7 @@ public class FallingBlockBehaviour extends EntityBehaviour<FallingBlockEntity> {
     }
 
     @Override
-    public void update(Caster<?> source, FallingBlockEntity entity, DisguiseSpell spell) {
+    public void update(Caster<?> source, FallingBlockEntity entity, Disguise spell) {
 
         BlockState state = entity.getBlockState();
         if (state.contains(Properties.WATERLOGGED)) {
@@ -98,7 +97,7 @@ public class FallingBlockBehaviour extends EntityBehaviour<FallingBlockEntity> {
             }
         }
 
-        Disguise disguise = spell.getDisguise();
+        EntityAppearance disguise = spell.getDisguise();
         List<Entity> attachments = disguise.getAttachments();
         if (attachments.size() > 0) {
             copyBaseAttributes(source.getMaster(), attachments.get(0), UP);
diff --git a/src/main/java/com/minelittlepony/unicopia/entity/behaviour/GhastBehaviour.java b/src/main/java/com/minelittlepony/unicopia/entity/behaviour/GhastBehaviour.java
index f0f1b2d2..e92d4d0e 100644
--- a/src/main/java/com/minelittlepony/unicopia/entity/behaviour/GhastBehaviour.java
+++ b/src/main/java/com/minelittlepony/unicopia/entity/behaviour/GhastBehaviour.java
@@ -1,6 +1,5 @@
 package com.minelittlepony.unicopia.entity.behaviour;
 
-import com.minelittlepony.unicopia.ability.magic.spell.DisguiseSpell;
 import com.minelittlepony.unicopia.entity.player.Pony;
 
 import net.minecraft.entity.mob.GhastEntity;
@@ -10,7 +9,7 @@ import net.minecraft.util.math.Vec3d;
 public class GhastBehaviour extends MobBehaviour<GhastEntity> {
 
     @Override
-    public void update(Pony player, GhastEntity entity, DisguiseSpell spell) {
+    public void update(Pony player, GhastEntity entity, Disguise spell) {
 
         if (player.sneakingChanged()) {
             boolean sneaking = player.getMaster().isSneaking();
diff --git a/src/main/java/com/minelittlepony/unicopia/entity/behaviour/HoppingBehaviour.java b/src/main/java/com/minelittlepony/unicopia/entity/behaviour/HoppingBehaviour.java
index 550ceddd..26c9ed0a 100644
--- a/src/main/java/com/minelittlepony/unicopia/entity/behaviour/HoppingBehaviour.java
+++ b/src/main/java/com/minelittlepony/unicopia/entity/behaviour/HoppingBehaviour.java
@@ -1,6 +1,5 @@
 package com.minelittlepony.unicopia.entity.behaviour;
 
-import com.minelittlepony.unicopia.ability.magic.spell.DisguiseSpell;
 import com.minelittlepony.unicopia.entity.player.Pony;
 
 import net.minecraft.entity.LivingEntity;
@@ -8,7 +7,7 @@ import net.minecraft.entity.passive.RabbitEntity;
 
 public class HoppingBehaviour extends EntityBehaviour<LivingEntity> {
     @Override
-    public void update(Pony player, LivingEntity entity, DisguiseSpell spell) {
+    public void update(Pony player, LivingEntity entity, Disguise spell) {
 
         if (player.getEntity().isOnGround()) {
             if (player.getEntity().getVelocity().horizontalLengthSquared() > 0.01) {
diff --git a/src/main/java/com/minelittlepony/unicopia/entity/behaviour/MinecartBehaviour.java b/src/main/java/com/minelittlepony/unicopia/entity/behaviour/MinecartBehaviour.java
index b000892d..48e1fead 100644
--- a/src/main/java/com/minelittlepony/unicopia/entity/behaviour/MinecartBehaviour.java
+++ b/src/main/java/com/minelittlepony/unicopia/entity/behaviour/MinecartBehaviour.java
@@ -2,7 +2,6 @@ package com.minelittlepony.unicopia.entity.behaviour;
 
 import com.minelittlepony.unicopia.InteractionManager;
 import com.minelittlepony.unicopia.ability.magic.Caster;
-import com.minelittlepony.unicopia.ability.magic.spell.DisguiseSpell;
 
 import net.minecraft.entity.LivingEntity;
 import net.minecraft.entity.vehicle.AbstractMinecartEntity;
@@ -10,7 +9,7 @@ import net.minecraft.entity.vehicle.AbstractMinecartEntity;
 public class MinecartBehaviour extends EntityBehaviour<AbstractMinecartEntity> {
 
     @Override
-    public AbstractMinecartEntity onCreate(AbstractMinecartEntity entity, Disguise context, boolean replaceOld) {
+    public AbstractMinecartEntity onCreate(AbstractMinecartEntity entity, EntityAppearance context, boolean replaceOld) {
         super.onCreate(entity, context, replaceOld);
         if (replaceOld && entity.world.isClient) {
             InteractionManager.instance().playLoopingSound(entity, InteractionManager.SOUND_MINECART);
@@ -19,7 +18,7 @@ public class MinecartBehaviour extends EntityBehaviour<AbstractMinecartEntity> {
     }
 
     @Override
-    public void update(Caster<?> source, AbstractMinecartEntity entity, DisguiseSpell spell) {
+    public void update(Caster<?> source, AbstractMinecartEntity entity, Disguise spell) {
         entity.setYaw(entity.getYaw() - 90);
         entity.prevYaw -= 90;
 
diff --git a/src/main/java/com/minelittlepony/unicopia/entity/behaviour/MobBehaviour.java b/src/main/java/com/minelittlepony/unicopia/entity/behaviour/MobBehaviour.java
index 1bc769cb..7cb297f1 100644
--- a/src/main/java/com/minelittlepony/unicopia/entity/behaviour/MobBehaviour.java
+++ b/src/main/java/com/minelittlepony/unicopia/entity/behaviour/MobBehaviour.java
@@ -1,6 +1,5 @@
 package com.minelittlepony.unicopia.entity.behaviour;
 
-import com.minelittlepony.unicopia.ability.magic.spell.DisguiseSpell;
 import com.minelittlepony.unicopia.entity.player.Pony;
 import com.minelittlepony.unicopia.util.RayTraceHelper;
 
@@ -18,7 +17,7 @@ public class MobBehaviour<T extends MobEntity> extends EntityBehaviour<T> {
     }
 
     @Override
-    public void update(Pony player, T entity, DisguiseSpell spell) {
+    public void update(Pony player, T entity, Disguise spell) {
         if (player.sneakingChanged() && isSneakingOnGround(player)) {
             LivingEntity target = findTarget(player, entity);
             entity.tryAttack(target);
diff --git a/src/main/java/com/minelittlepony/unicopia/entity/behaviour/PlayerBehaviour.java b/src/main/java/com/minelittlepony/unicopia/entity/behaviour/PlayerBehaviour.java
index 964cdf79..9de9eb71 100644
--- a/src/main/java/com/minelittlepony/unicopia/entity/behaviour/PlayerBehaviour.java
+++ b/src/main/java/com/minelittlepony/unicopia/entity/behaviour/PlayerBehaviour.java
@@ -1,7 +1,6 @@
 package com.minelittlepony.unicopia.entity.behaviour;
 
 import com.minelittlepony.unicopia.ability.magic.Caster;
-import com.minelittlepony.unicopia.ability.magic.spell.DisguiseSpell;
 import com.minelittlepony.unicopia.entity.CapeHolder;
 import com.minelittlepony.unicopia.entity.Leaner;
 import com.minelittlepony.unicopia.entity.player.Pony;
@@ -10,7 +9,7 @@ import net.minecraft.entity.player.PlayerEntity;
 
 public class PlayerBehaviour extends EntityBehaviour<PlayerEntity> {
     @Override
-    public void update(Caster<?> source, PlayerEntity entity, DisguiseSpell spell) {
+    public void update(Caster<?> source, PlayerEntity entity, Disguise spell) {
         if (source instanceof Pony) {
             PlayerEntity pFrom = ((Pony)source).getMaster();
 
diff --git a/src/main/java/com/minelittlepony/unicopia/entity/behaviour/RangedAttackBehaviour.java b/src/main/java/com/minelittlepony/unicopia/entity/behaviour/RangedAttackBehaviour.java
index 38bbc0ee..e0cd3c80 100644
--- a/src/main/java/com/minelittlepony/unicopia/entity/behaviour/RangedAttackBehaviour.java
+++ b/src/main/java/com/minelittlepony/unicopia/entity/behaviour/RangedAttackBehaviour.java
@@ -2,7 +2,6 @@ package com.minelittlepony.unicopia.entity.behaviour;
 
 import java.util.function.BiFunction;
 
-import com.minelittlepony.unicopia.ability.magic.spell.DisguiseSpell;
 import com.minelittlepony.unicopia.entity.player.Pony;
 
 import net.minecraft.entity.Entity;
@@ -24,7 +23,7 @@ public class RangedAttackBehaviour<T extends Entity & RangedAttackMob> extends E
     }
 
     @Override
-    public void update(Pony player, T entity, DisguiseSpell spell) {
+    public void update(Pony player, T entity, Disguise spell) {
 
         if (player.sneakingChanged() && isSneakingOnGround(player)) {
 
diff --git a/src/main/java/com/minelittlepony/unicopia/entity/behaviour/SheepBehaviour.java b/src/main/java/com/minelittlepony/unicopia/entity/behaviour/SheepBehaviour.java
index b402fb21..8c3058c7 100644
--- a/src/main/java/com/minelittlepony/unicopia/entity/behaviour/SheepBehaviour.java
+++ b/src/main/java/com/minelittlepony/unicopia/entity/behaviour/SheepBehaviour.java
@@ -2,7 +2,6 @@ package com.minelittlepony.unicopia.entity.behaviour;
 
 import java.util.Random;
 
-import com.minelittlepony.unicopia.ability.magic.spell.DisguiseSpell;
 import com.minelittlepony.unicopia.entity.player.Pony;
 import com.minelittlepony.unicopia.mixin.MixinSheepEntity;
 
@@ -19,7 +18,7 @@ import net.minecraft.world.WorldEvents;
 
 public class SheepBehaviour extends EntityBehaviour<SheepEntity> {
     @Override
-    public void update(Pony player, SheepEntity entity, DisguiseSpell spell) {
+    public void update(Pony player, SheepEntity entity, Disguise spell) {
 
         if (player.sneakingChanged()) {
 
diff --git a/src/main/java/com/minelittlepony/unicopia/entity/behaviour/ShulkerBehaviour.java b/src/main/java/com/minelittlepony/unicopia/entity/behaviour/ShulkerBehaviour.java
index 0ec861db..c0e14f7f 100644
--- a/src/main/java/com/minelittlepony/unicopia/entity/behaviour/ShulkerBehaviour.java
+++ b/src/main/java/com/minelittlepony/unicopia/entity/behaviour/ShulkerBehaviour.java
@@ -1,7 +1,6 @@
 package com.minelittlepony.unicopia.entity.behaviour;
 
 import com.minelittlepony.unicopia.ability.magic.Caster;
-import com.minelittlepony.unicopia.ability.magic.spell.DisguiseSpell;
 import com.minelittlepony.unicopia.entity.player.Pony;
 import com.minelittlepony.unicopia.mixin.MixinShulkerEntity;
 
@@ -15,7 +14,7 @@ import net.minecraft.util.math.Vec3d;
 
 public class ShulkerBehaviour extends EntityBehaviour<ShulkerEntity> {
     @Override
-    public void update(Caster<?> source, ShulkerEntity shulker, DisguiseSpell spell) {
+    public void update(Caster<?> source, ShulkerEntity shulker, Disguise spell) {
         shulker.setYaw(0);
         shulker.prevBodyYaw = 0;
         shulker.bodyYaw = 0;
@@ -38,7 +37,7 @@ public class ShulkerBehaviour extends EntityBehaviour<ShulkerEntity> {
     }
 
     @Override
-    protected void update(Pony player, ShulkerEntity shulker, DisguiseSpell spell) {
+    protected void update(Pony player, ShulkerEntity shulker, Disguise spell) {
         float peekAmount = 30;
 
         double speed = !player.getEntity().isSneaking() ? 0.29 : 0;
diff --git a/src/main/java/com/minelittlepony/unicopia/entity/behaviour/SilverfishBehaviour.java b/src/main/java/com/minelittlepony/unicopia/entity/behaviour/SilverfishBehaviour.java
index 0d5fe705..eb5c4a06 100644
--- a/src/main/java/com/minelittlepony/unicopia/entity/behaviour/SilverfishBehaviour.java
+++ b/src/main/java/com/minelittlepony/unicopia/entity/behaviour/SilverfishBehaviour.java
@@ -1,6 +1,5 @@
 package com.minelittlepony.unicopia.entity.behaviour;
 
-import com.minelittlepony.unicopia.ability.magic.spell.DisguiseSpell;
 import com.minelittlepony.unicopia.block.state.StateMaps;
 import com.minelittlepony.unicopia.entity.player.Pony;
 
@@ -12,7 +11,7 @@ import net.minecraft.world.WorldEvents;
 
 public class SilverfishBehaviour extends EntityBehaviour<SilverfishEntity> {
     @Override
-    public void update(Pony player, SilverfishEntity entity, DisguiseSpell spell) {
+    public void update(Pony player, SilverfishEntity entity, Disguise spell) {
         if (!player.isClient() && player.sneakingChanged() && player.getMaster().isSneaking()) {
             BlockPos pos = entity.getBlockPos().down();
             BlockState state = entity.world.getBlockState(pos);
diff --git a/src/main/java/com/minelittlepony/unicopia/entity/behaviour/SpellcastingIllagerBehaviour.java b/src/main/java/com/minelittlepony/unicopia/entity/behaviour/SpellcastingIllagerBehaviour.java
index ec4c71d5..b3acfc67 100644
--- a/src/main/java/com/minelittlepony/unicopia/entity/behaviour/SpellcastingIllagerBehaviour.java
+++ b/src/main/java/com/minelittlepony/unicopia/entity/behaviour/SpellcastingIllagerBehaviour.java
@@ -1,13 +1,12 @@
 package com.minelittlepony.unicopia.entity.behaviour;
 
-import com.minelittlepony.unicopia.ability.magic.spell.DisguiseSpell;
 import com.minelittlepony.unicopia.entity.player.Pony;
 
 import net.minecraft.entity.mob.SpellcastingIllagerEntity;
 
 public class SpellcastingIllagerBehaviour extends EntityBehaviour<SpellcastingIllagerEntity> {
     @Override
-    public void update(Pony player, SpellcastingIllagerEntity entity, DisguiseSpell s) {
+    public void update(Pony player, SpellcastingIllagerEntity entity, Disguise s) {
         if (player.sneakingChanged()) {
             SpellCastAccess.setSpell(player, entity, s);
         }
@@ -16,7 +15,7 @@ public class SpellcastingIllagerBehaviour extends EntityBehaviour<SpellcastingIl
     private static abstract class SpellCastAccess extends SpellcastingIllagerEntity {
         SpellCastAccess() {super(null, null);}
 
-        static void setSpell(Pony player, SpellcastingIllagerEntity entity, DisguiseSpell s) {
+        static void setSpell(Pony player, SpellcastingIllagerEntity entity, Disguise s) {
             if (player.getMaster().isSneaking()) {
                 SpellcastingIllagerEntity.Spell[] spells = SpellcastingIllagerEntity.Spell.values();
                 SpellcastingIllagerEntity.Spell spell = spells[entity.world.random.nextInt(spells.length - 1) + 1];
diff --git a/src/main/java/com/minelittlepony/unicopia/entity/behaviour/SteedBehaviour.java b/src/main/java/com/minelittlepony/unicopia/entity/behaviour/SteedBehaviour.java
index 18550cc7..7b6f90cb 100644
--- a/src/main/java/com/minelittlepony/unicopia/entity/behaviour/SteedBehaviour.java
+++ b/src/main/java/com/minelittlepony/unicopia/entity/behaviour/SteedBehaviour.java
@@ -1,6 +1,5 @@
 package com.minelittlepony.unicopia.entity.behaviour;
 
-import com.minelittlepony.unicopia.ability.magic.spell.DisguiseSpell;
 import com.minelittlepony.unicopia.entity.player.Pony;
 
 import net.minecraft.entity.JumpingMount;
@@ -10,7 +9,7 @@ import net.minecraft.entity.passive.HorseBaseEntity;
 public class SteedBehaviour<T extends LivingEntity & JumpingMount> extends EntityBehaviour<T> {
 
     @Override
-    public void update(Pony player, T entity, DisguiseSpell spell) {
+    public void update(Pony player, T entity, Disguise spell) {
 
         HorseBaseEntity horse = ((HorseBaseEntity)entity);
 
diff --git a/src/main/java/com/minelittlepony/unicopia/entity/behaviour/TraderBehaviour.java b/src/main/java/com/minelittlepony/unicopia/entity/behaviour/TraderBehaviour.java
index 789e9194..46af39a9 100644
--- a/src/main/java/com/minelittlepony/unicopia/entity/behaviour/TraderBehaviour.java
+++ b/src/main/java/com/minelittlepony/unicopia/entity/behaviour/TraderBehaviour.java
@@ -1,6 +1,5 @@
 package com.minelittlepony.unicopia.entity.behaviour;
 
-import com.minelittlepony.unicopia.ability.magic.spell.DisguiseSpell;
 import com.minelittlepony.unicopia.entity.player.Pony;
 
 import net.minecraft.entity.passive.MerchantEntity;
@@ -8,7 +7,7 @@ import net.minecraft.sound.SoundEvents;
 
 public class TraderBehaviour extends EntityBehaviour<MerchantEntity> {
     @Override
-    public void update(Pony pony, MerchantEntity entity, DisguiseSpell spell) {
+    public void update(Pony pony, MerchantEntity entity, Disguise spell) {
         if (pony.sneakingChanged() && pony.getMaster().isSneaking()) {
             entity.setHeadRollingTimeLeft(40);
 
diff --git a/src/main/java/com/minelittlepony/unicopia/entity/behaviour/WaterCreatureBehaviour.java b/src/main/java/com/minelittlepony/unicopia/entity/behaviour/WaterCreatureBehaviour.java
index 784c35b2..63408f6a 100644
--- a/src/main/java/com/minelittlepony/unicopia/entity/behaviour/WaterCreatureBehaviour.java
+++ b/src/main/java/com/minelittlepony/unicopia/entity/behaviour/WaterCreatureBehaviour.java
@@ -1,14 +1,13 @@
 package com.minelittlepony.unicopia.entity.behaviour;
 
 import com.minelittlepony.unicopia.ability.magic.Caster;
-import com.minelittlepony.unicopia.ability.magic.spell.DisguiseSpell;
 
 import net.minecraft.entity.damage.DamageSource;
 import net.minecraft.entity.mob.WaterCreatureEntity;
 
 public class WaterCreatureBehaviour extends EntityBehaviour<WaterCreatureEntity> {
     @Override
-    public void update(Caster<?> source, WaterCreatureEntity entity, DisguiseSpell spell) {
+    public void update(Caster<?> source, WaterCreatureEntity entity, Disguise spell) {
 
         if (source.getEntity().isInsideWaterOrBubbleColumn()) {
             source.getEntity().setAir(source.getEntity().getAir() - 1);
diff --git a/src/main/java/com/minelittlepony/unicopia/entity/player/PlayerCamera.java b/src/main/java/com/minelittlepony/unicopia/entity/player/PlayerCamera.java
index 233e572e..9825b8ba 100644
--- a/src/main/java/com/minelittlepony/unicopia/entity/player/PlayerCamera.java
+++ b/src/main/java/com/minelittlepony/unicopia/entity/player/PlayerCamera.java
@@ -3,8 +3,8 @@ package com.minelittlepony.unicopia.entity.player;
 import java.util.Optional;
 
 import com.minelittlepony.common.util.animation.MotionCompositor;
-import com.minelittlepony.unicopia.ability.magic.spell.DisguiseSpell;
-import com.minelittlepony.unicopia.ability.magic.spell.effect.SpellType;
+import com.minelittlepony.unicopia.ability.magic.SpellPredicate;
+import com.minelittlepony.unicopia.ability.magic.spell.AbstractDisguiseSpell;
 
 import net.minecraft.util.math.Vec3d;
 
@@ -48,8 +48,8 @@ public class PlayerCamera extends MotionCompositor {
 
     public Optional<Double> calculateDistance(double distance) {
         return player.getSpellSlot()
-            .get(SpellType.DISGUISE, false)
-            .map(DisguiseSpell::getDisguise)
+            .get(SpellPredicate.IS_DISGUISE, false)
+            .map(AbstractDisguiseSpell::getDisguise)
             .flatMap(d -> d.getDistance(player))
             .map(d -> distance * d);
     }
diff --git a/src/main/java/com/minelittlepony/unicopia/entity/player/PlayerPhysics.java b/src/main/java/com/minelittlepony/unicopia/entity/player/PlayerPhysics.java
index 200cd960..f62274d7 100644
--- a/src/main/java/com/minelittlepony/unicopia/entity/player/PlayerPhysics.java
+++ b/src/main/java/com/minelittlepony/unicopia/entity/player/PlayerPhysics.java
@@ -4,6 +4,7 @@ import com.minelittlepony.unicopia.FlightType;
 import com.minelittlepony.unicopia.InteractionManager;
 import com.minelittlepony.unicopia.Race;
 import com.minelittlepony.unicopia.USounds;
+import com.minelittlepony.unicopia.ability.magic.SpellPredicate;
 import com.minelittlepony.unicopia.ability.magic.spell.effect.SpellType;
 import com.minelittlepony.unicopia.advancement.UCriteria;
 import com.minelittlepony.unicopia.entity.Creature;
@@ -258,7 +259,7 @@ public class PlayerPhysics extends EntityPhysics<PlayerEntity> implements Tickab
                     prevStrafe = strafing;
                     strafe = 1;
                     ticksToGlide = MAX_TICKS_TO_GLIDE;
-                    if (!SpellType.DISGUISE.isOn(pony)) {
+                    if (!SpellPredicate.IS_DISGUISE.isOn(pony)) {
                         entity.playSound(type.getWingFlapSound(), 0.25F, 1);
                     }
                 } else {
@@ -334,7 +335,7 @@ public class PlayerPhysics extends EntityPhysics<PlayerEntity> implements Tickab
                 ticksToGlide = MAX_TICKS_TO_GLIDE;
             }
 
-            if (!SpellType.DISGUISE.isOn(pony)) {
+            if (!SpellPredicate.IS_DISGUISE.isOn(pony)) {
                 if (ticksInAir % GLIDING_SOUND_INTERVAL == 1 && pony.isClient()) {
                     InteractionManager.instance().playLoopingSound(entity, InteractionManager.SOUND_GLIDING);
                 }
@@ -343,7 +344,7 @@ public class PlayerPhysics extends EntityPhysics<PlayerEntity> implements Tickab
             velocity.y -= 0.02 * getGravitySignum();
             velocity.x *= 0.9896;
             velocity.z *= 0.9896;
-        } else if (type == FlightType.INSECTOID && !SpellType.DISGUISE.isOn(pony)) {
+        } else if (type == FlightType.INSECTOID && !SpellPredicate.IS_DISGUISE.isOn(pony)) {
             if (entity.world.isClient && !soundPlaying) {
                 soundPlaying = true;
                 InteractionManager.instance().playLoopingSound(entity, InteractionManager.SOUND_CHANGELING_BUZZ);
@@ -496,7 +497,7 @@ public class PlayerPhysics extends EntityPhysics<PlayerEntity> implements Tickab
 
         if (thrustScale <= 0.000001F & flapping) {
             flapping = false;
-            if (!SpellType.DISGUISE.isOn(pony)) {
+            if (!SpellPredicate.IS_DISGUISE.isOn(pony)) {
                 entity.playSound(getFlightType().getWingFlapSound(), 0.5F, 1);
             }
             thrustScale = 1;
diff --git a/src/main/java/com/minelittlepony/unicopia/mixin/MixinLivingEntity.java b/src/main/java/com/minelittlepony/unicopia/mixin/MixinLivingEntity.java
index 54d72ebc..0f20bc60 100644
--- a/src/main/java/com/minelittlepony/unicopia/mixin/MixinLivingEntity.java
+++ b/src/main/java/com/minelittlepony/unicopia/mixin/MixinLivingEntity.java
@@ -13,11 +13,11 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
 import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
 
 import com.minelittlepony.unicopia.ability.magic.Caster;
-import com.minelittlepony.unicopia.ability.magic.spell.DisguiseSpell;
-import com.minelittlepony.unicopia.ability.magic.spell.effect.SpellType;
+import com.minelittlepony.unicopia.ability.magic.SpellPredicate;
+import com.minelittlepony.unicopia.ability.magic.spell.AbstractDisguiseSpell;
 import com.minelittlepony.unicopia.entity.Creature;
 import com.minelittlepony.unicopia.entity.PonyContainer;
-import com.minelittlepony.unicopia.entity.behaviour.Disguise;
+import com.minelittlepony.unicopia.entity.behaviour.EntityAppearance;
 import com.minelittlepony.unicopia.entity.player.Pony;
 import com.minelittlepony.unicopia.entity.Equine;
 import com.minelittlepony.unicopia.entity.ItemWielder;
@@ -91,9 +91,9 @@ abstract class MixinLivingEntity extends Entity implements PonyContainer<Equine<
     @Inject(method = "isClimbing()Z", at = @At("HEAD"), cancellable = true)
     public void onIsClimbing(CallbackInfoReturnable<Boolean> info) {
         if (get() instanceof Pony && horizontalCollision) {
-            ((Pony)get()).getSpellSlot().get(SpellType.DISGUISE, false)
-            .map(DisguiseSpell::getDisguise)
-            .filter(Disguise::canClimbWalls)
+            ((Pony)get()).getSpellSlot().get(SpellPredicate.IS_DISGUISE, false)
+            .map(AbstractDisguiseSpell::getDisguise)
+            .filter(EntityAppearance::canClimbWalls)
             .ifPresent(v -> {
                 climbingPos = Optional.of(getBlockPos());
                 info.setReturnValue(true);
@@ -104,9 +104,9 @@ abstract class MixinLivingEntity extends Entity implements PonyContainer<Equine<
     @Inject(method = "isPushable()Z", at = @At("HEAD"), cancellable = true)
     private void onIsPushable(CallbackInfoReturnable<Boolean> info) {
         Caster.of(this)
-            .flatMap(c -> c.getSpellSlot().get(SpellType.DISGUISE, false))
-            .map(DisguiseSpell::getDisguise)
-            .map(Disguise::getAppearance)
+            .flatMap(c -> c.getSpellSlot().get(SpellPredicate.IS_DISGUISE, false))
+            .map(AbstractDisguiseSpell::getDisguise)
+            .map(EntityAppearance::getAppearance)
             .filter(Entity::isPushable)
             .ifPresent(v -> {
                 info.setReturnValue(false);
diff --git a/src/main/java/com/minelittlepony/unicopia/mixin/MixinTargetPredicate.java b/src/main/java/com/minelittlepony/unicopia/mixin/MixinTargetPredicate.java
index 9b77c98b..34610cb0 100644
--- a/src/main/java/com/minelittlepony/unicopia/mixin/MixinTargetPredicate.java
+++ b/src/main/java/com/minelittlepony/unicopia/mixin/MixinTargetPredicate.java
@@ -7,7 +7,7 @@ import org.spongepowered.asm.mixin.injection.At;
 import org.spongepowered.asm.mixin.injection.Inject;
 import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
 
-import com.minelittlepony.unicopia.ability.magic.spell.effect.SpellType;
+import com.minelittlepony.unicopia.ability.magic.SpellPredicate;
 import com.minelittlepony.unicopia.entity.Equine;
 import com.minelittlepony.unicopia.entity.player.Pony;
 
@@ -20,7 +20,7 @@ abstract class MixinTargetPredicate {
     public void onTest(@Nullable LivingEntity baseEntity, LivingEntity targetEntity, CallbackInfoReturnable<Boolean> info) {
         Equine<?> eq = Equine.of(targetEntity).orElse(null);
         if (eq instanceof Pony) {
-            ((Pony)eq).getSpellSlot().get(SpellType.DISGUISE, true).ifPresent(spell -> {
+            ((Pony)eq).getSpellSlot().get(SpellPredicate.IS_DISGUISE, true).ifPresent(spell -> {
                 if (spell.getDisguise().getAppearance() == baseEntity) {
                     info.setReturnValue(false);
                 }
diff --git a/src/main/java/com/minelittlepony/unicopia/mixin/MixinWorld.java b/src/main/java/com/minelittlepony/unicopia/mixin/MixinWorld.java
index ec9fbf49..7f8264b5 100644
--- a/src/main/java/com/minelittlepony/unicopia/mixin/MixinWorld.java
+++ b/src/main/java/com/minelittlepony/unicopia/mixin/MixinWorld.java
@@ -14,7 +14,7 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
 
 import com.minelittlepony.unicopia.BlockDestructionManager;
 import com.minelittlepony.unicopia.entity.RotatedView;
-import com.minelittlepony.unicopia.entity.behaviour.Disguise;
+import com.minelittlepony.unicopia.entity.behaviour.EntityAppearance;
 
 import net.minecraft.block.BlockState;
 import net.minecraft.entity.Entity;
@@ -50,7 +50,7 @@ abstract class MixinWorld implements WorldAccess, BlockDestructionManager.Source
     @Override
     public List<VoxelShape> getEntityCollisions(@Nullable Entity entity, Box box) {
         if (box.getAverageSideLength() >= 1.0E-7D) {
-            List<VoxelShape> shapes = Disguise.getColissonShapes(entity, this, box);
+            List<VoxelShape> shapes = EntityAppearance.getColissonShapes(entity, this, box);
             if (!shapes.isEmpty()) {
                 return Stream.concat(shapes.stream(), WorldAccess.super.getEntityCollisions(entity, box).stream()).toList();
             }