diff --git a/js/003-data/gameVariableData.js b/js/003-data/gameVariableData.js
index ded5a1b0ef6297493ba9d3dee9213972a55a5178..d71f25e8d316504cdcf1678c3790417aea99a989 100644
--- a/js/003-data/gameVariableData.js
+++ b/js/003-data/gameVariableData.js
@@ -755,7 +755,8 @@ App.Data.resetOnNGPlus = {
 		/** @type {string[]} */
 		feline: [],
 	},
-	customAnimals: [],
+	/** @type {Map<string, App.Entity.Animal>} */
+	customAnimals: new Map,
 	farmyardName: "the Farmyard",
 
 	HGSuite: 0,
diff --git a/src/data/backwardsCompatibility/farmyardBC.js b/src/data/backwardsCompatibility/farmyardBC.js
index 79daceddd6f15e8a9bbedd2bbed77aac21de69d3..ff48d37a05d4a4e438d152ee89c8a2e815adac13 100644
--- a/src/data/backwardsCompatibility/farmyardBC.js
+++ b/src/data/backwardsCompatibility/farmyardBC.js
@@ -6,7 +6,9 @@ App.Facilities.Farmyard.BC = function() {
 		};
 	}
 
-	App.Facilities.Farmyard.animals.validate();
+	if (App.Data.Animals.size === 0) {
+		App.Facilities.Farmyard.animals.init();
+	}
 
 	if (V.foodStored) {
 		V.mods.food.amount += V.foodStored;
diff --git a/src/facilities/farmyard/animals/Animal.js b/src/facilities/farmyard/animals/Animal.js
index 4728b063350818998bf9acd6a87bc96bd10f0c44..423c0de0a20663d17a33561ad451b21a4c3893ab 100644
--- a/src/facilities/farmyard/animals/Animal.js
+++ b/src/facilities/farmyard/animals/Animal.js
@@ -1,13 +1,14 @@
 /** The base animal class. */
-App.Entity.Animal = class Animal {
+App.Entity.Animal = class Animal extends App.Entity.Serializable {
 	/**
 	 * @param {string} name
 	 * @param {string} species
 	 * @param {'canine'|'hooved'|'feline'} type
 	 * @param {'domestic'|'exotic'} rarity
-	 * @param {string} [uuid]
+	 * @param {string} [uuid] used by custom animals
 	 */
 	constructor(name, species, type, rarity, uuid) {
+		super();
 		this.name = name;
 		this.species = species;
 		this.type = type;
@@ -72,11 +73,7 @@ App.Entity.Animal = class Animal {
 	}
 
 	remove() {
-		const index = V.customAnimals.findIndex(animal => animal.name === this.name);
-		if (~index) {
-			V.customAnimals.splice(index, 1);
-		}
-		App.Data.animals.delete(this);
+		V.customAnimals.delete(this.name);
 	}
 
 	/** @param {string} name */
@@ -138,4 +135,17 @@ App.Entity.Animal = class Animal {
 
 		return this;
 	}
+
+	static _cleanupConfigScheme(config) {
+		super._cleanupConfigScheme(config);
+		// BC code
+	}
+
+	/** @returns {Animal} */
+	clone() {
+		// @ts-ignore
+		return (new Animal)._init(this);
+	}
+
+	get className() { return "App.Entity.Animal"; }
 };
diff --git a/src/facilities/farmyard/animals/animals.js b/src/facilities/farmyard/animals/animals.js
index 3666783ca89b512bfd1a2a3a6927416bc93d4865..145cc07f7e6f04a8b5447c96fec89fce8af615ff 100644
--- a/src/facilities/farmyard/animals/animals.js
+++ b/src/facilities/farmyard/animals/animals.js
@@ -1,6 +1,6 @@
 App.Facilities.Farmyard.animals = function() {
-	if (!App.Data.animals || App.Data.animals.size === 0) {
-		App.Facilities.Farmyard.animals.validate();
+	if (App.Data.Animals.size === 0) {
+		App.Facilities.Farmyard.animals.init();
 	}
 
 	const frag = new DocumentFragment();
@@ -548,8 +548,7 @@ App.Facilities.Farmyard.animals = function() {
 				App.UI.DOM.appendNewElement("div", addDiv, App.UI.DOM.disabledLink(`Add`, disabledReasons), ['margin-top']);
 			} else {
 				App.UI.DOM.appendNewElement("div", addDiv, App.UI.DOM.link(`Add`, () => {
-					App.Data.animals.add(animal);
-					V.customAnimals.push(animal);
+					V.customAnimals.set(animal.name, animal);
 
 					App.UI.reload();
 				}), ['margin-top']);
@@ -577,37 +576,15 @@ App.Facilities.Farmyard.animals = function() {
  * @returns {App.Entity.Animal}
  */
 globalThis.getAnimal = function(name) {
-	App.Facilities.Farmyard.animals.validate();
-
-	return [...App.Data.animals].find(animal => animal.name === name);
-};
-
-/** @param {App.Entity.Animal} data */
-function restoreAnimal(data) {
-	const {
-		name, species, type, rarity, dick, deadliness, articleAn, uuid
-	} = data;
-	if (!name || !species || !type || !rarity || !uuid) {
-		return;
+	if (App.Data.Animals.size === 0) {
+		App.Facilities.Farmyard.animals.init();
 	}
 
-	const animal = new App.Entity.Animal(name, species, type, rarity, uuid);
-
-	if (dick && dick.size) {
-		animal.setDick(dick.size, dick.desc);
-	}
-	if (deadliness) {
-		animal.setDeadliness(deadliness);
-	}
-	if (articleAn && (articleAn === 'a' || articleAn === 'an')) {
-		animal.setArticle(articleAn);
-	}
-	return animal;
-}
+	return V.customAnimals.get(name) ?? App.Data.Animals.get(name);
+};
 
-/** Ensures App.Data.animals exists and has user's custom animals */
-App.Facilities.Farmyard.animals.validate = function() {
-	if (!App.Data.animals || App.Data.animals.size === 0) {
+App.Facilities.Farmyard.animals.init = function() {
+	if (App.Data.Animals.size === 0) {
 		class Animal extends App.Entity.Animal { }
 
 		const dog = 'dog';
@@ -674,38 +651,15 @@ App.Facilities.Farmyard.animals.validate = function() {
 			new Animal("lynx", "lynx", feline, exotic),
 			new Animal("puma", "puma", feline, exotic),
 			new Animal("tiger", "tiger", feline, exotic),
-		].forEach(animal => App.Data.animals.add(animal));
+		].forEach(animal => App.Data.Animals.set(animal.name, animal));
 	}
+};
 
-	const appData = [...App.Data.animals];
-	const customAnimals = new Set;
+/** @type {Map<string, App.Entity.Animal>} */
+App.Data.Animals = new Map;
 
-	if (V.customAnimals.length) {
-		for (const animalData of V.customAnimals) {
-			if (animalData.uuid && appData.some(animal => animal.uuid === animalData.uuid)) {
-				customAnimals.add(animalData.uuid);
-				continue;
-			}
-			const animal = restoreAnimal(animalData);
-			if (animal) {
-				const existing = appData.filter(a => a.name === animal.name);
-				if (existing.length) {
-					existing.forEach(e => e.remove());
-				}
-				App.Data.animals.add(animal);
-				customAnimals.add(animal.uuid);
-			} else {
-				animalData.invalid = true;
-				console.error('Invalid custom animal set for removal:', animalData);
-			}
-		}
-		V.customAnimals = V.customAnimals.filter(d => !d.invalid);
+Object.defineProperty(App.Data, 'animals', {
+	get() {
+		return [...App.Data.Animals.values(), ...V.customAnimals.values()];
 	}
-
-	appData.filter(a => a.isCustom && !customAnimals.has(a.uuid)).forEach(a => {
-		a.remove();
-	});
-};
-
-/** @type {Set<App.Entity.Animal>} */
-App.Data.animals ??= new Set;
+});