--- a/net/minecraft/world/entity/Leashable.java
+++ b/net/minecraft/world/entity/Leashable.java
@@ -56,7 +_,13 @@
     @Nullable
     private static Leashable.LeashData readLeashDataInternal(CompoundTag tag) {
         if (tag.contains("leash", 10)) {
-            return new Leashable.LeashData(Either.left(tag.getCompound("leash").getUUID("UUID")));
+            // Paper start
+            final CompoundTag leashTag = tag.getCompound("leash");
+            if (!leashTag.hasUUID("UUID")) {
+                return null;
+            }
+            return new Leashable.LeashData(Either.left(leashTag.getUUID("UUID")));
+            // Paper end
         } else {
             if (tag.contains("leash", 11)) {
                 Either<UUID, BlockPos> either = NbtUtils.readBlockPos(tag, "leash").<Either<UUID, BlockPos>>map(Either::right).orElse(null);
@@ -72,6 +_,11 @@
     default void writeLeashData(CompoundTag tag, @Nullable Leashable.LeashData leashData) {
         if (leashData != null) {
             Either<UUID, BlockPos> either = leashData.delayedLeashInfo;
+            // CraftBukkit start - SPIGOT-7487: Don't save (and possible drop) leash, when the holder was removed by a plugin
+            if (leashData.leashHolder != null && leashData.leashHolder.pluginRemoved) {
+                return;
+            }
+            // CraftBukkit end
             if (leashData.leashHolder instanceof LeashFenceKnotEntity leashFenceKnotEntity) {
                 either = Either.right(leashFenceKnotEntity.getPos());
             } else if (leashData.leashHolder != null) {
@@ -104,7 +_,9 @@
             }
 
             if (entity.tickCount > 100) {
+                entity.forceDrops = true; // CraftBukkit
                 entity.spawnAtLocation(serverLevel, Items.LEAD);
+                entity.forceDrops = false; // CraftBukkit
                 entity.setLeashData(null);
             }
         }
@@ -128,7 +_,9 @@
             entity.onLeashRemoved();
             if (entity.level() instanceof ServerLevel serverLevel) {
                 if (dropItem) {
+                    entity.forceDrops = true; // CraftBukkit
                     entity.spawnAtLocation(serverLevel, Items.LEAD);
+                    entity.forceDrops = false; // CraftBukkit
                 }
 
                 if (broadcastPacket) {
@@ -146,7 +_,15 @@
 
         if (leashData != null && leashData.leashHolder != null) {
             if (!entity.isAlive() || !leashData.leashHolder.isAlive()) {
-                if (level.getGameRules().getBoolean(GameRules.RULE_DOENTITYDROPS)) {
+                // Paper start - Expand EntityUnleashEvent
+                final org.bukkit.event.entity.EntityUnleashEvent event = new org.bukkit.event.entity.EntityUnleashEvent(
+                    entity.getBukkitEntity(),
+                    !entity.isAlive() ? org.bukkit.event.entity.EntityUnleashEvent.UnleashReason.PLAYER_UNLEASH : org.bukkit.event.entity.EntityUnleashEvent.UnleashReason.HOLDER_GONE,
+                    level.getGameRules().getBoolean(GameRules.RULE_DOENTITYDROPS) && !entity.pluginRemoved
+                );
+                event.callEvent();
+                if (event.isDropLeash()) { // CraftBukkit - SPIGOT-7487: Don't drop leash, when the holder was removed by a plugin
+                    // Paper end - Expand EntityUnleashEvent
                     entity.dropLeash();
                 } else {
                     entity.removeLeash();
@@ -160,7 +_,7 @@
                     return;
                 }
 
-                if (f > 10.0) {
+                if (f > entity.level().paperConfig().misc.maxLeashDistance.or(LEASH_TOO_FAR_DIST)) { // Paper - Configurable max leash distance
                     entity.leashTooFarBehaviour();
                 } else if (f > 6.0) {
                     entity.elasticRangeLeashBehaviour(leashHolder, f);
@@ -177,7 +_,21 @@
     }
 
     default void leashTooFarBehaviour() {
-        this.dropLeash();
+        // CraftBukkit start
+        boolean dropLeash = true; // Paper
+        if (this instanceof Entity entity) {
+            // Paper start - Expand EntityUnleashEvent
+            final org.bukkit.event.entity.EntityUnleashEvent event = new org.bukkit.event.entity.EntityUnleashEvent(entity.getBukkitEntity(), org.bukkit.event.entity.EntityUnleashEvent.UnleashReason.DISTANCE, true);
+            if (!event.callEvent()) return;
+            dropLeash = event.isDropLeash();
+        }
+        // CraftBukkit end
+        if (dropLeash) {
+            this.dropLeash();
+        } else {
+            this.removeLeash();
+        }
+        // Paper end - Expand EntityUnleashEvent
     }
 
     default void closeRangeLeashBehaviour(Entity entity) {
