diff --git a/Assets/Scripts/Fighter.cs b/Assets/Scripts/Fighter.cs
new file mode 100644
index 0000000000000000000000000000000000000000..078202b480350cf6679206e19f09da3142db045e
--- /dev/null
+++ b/Assets/Scripts/Fighter.cs
@@ -0,0 +1,88 @@
+using System.Collections;
+using System.Collections.Generic;
+using UnityEngine;
+
+public interface IFighterCallback
+{
+    void OnDeath();
+}
+
+// Generic subclass for any Fighter on the field, whether it's an Enemy or the AntiPlayer.
+// Contains stats management such as health, attacks, damage, death, etc.
+public abstract class Fighter : MonoBehaviour
+{
+
+    [SerializeField] int baseHealth = 100;
+    [SerializeField, Tooltip("Attack every x ms")] int baseAttackSpeed = 1000;
+    [SerializeField] int baseAttackDamage = 10;
+    [SerializeField] int baseArmor = 1;
+
+    public List<IFighterCallback> callbacks = new List<IFighterCallback>();
+
+    protected int currentHealth = 100;
+    protected Animator animator;
+    protected bool alive { get => currentHealth > 0; }
+    protected FighterTypes fighterType;
+    protected abstract void Attack();
+
+    float timeSinceLastAttack = 0f;
+
+    protected virtual void Awake()
+    {
+        animator = GetComponent<Animator>();
+        fighterType = FighterTypes.ENEMY;
+    }
+
+    protected virtual void Start()
+    {
+        currentHealth = Mathf.RoundToInt(baseHealth * GetStats().healthMultiplier);
+    }
+
+    protected virtual void Update()
+    {
+        if (alive)
+        {
+            timeSinceLastAttack += Time.deltaTime;
+            var timeUntilNextAttack = baseAttackSpeed - timeSinceLastAttack;
+            if (timeUntilNextAttack <= 0)
+            {
+                Attack();
+                // TODO delegate to subclass? Some attack animations take time to charge up.
+                animator.SetTrigger("Attack");
+                timeSinceLastAttack = -timeUntilNextAttack; // To account for overshoot
+            }
+        }
+    }
+
+    public void DealDamage(int dmg)
+    {
+        var actualDamage = Mathf.Max(0, Mathf.RoundToInt(dmg - baseArmor * GetStats().armorMultiplier));
+        currentHealth = Mathf.Max(currentHealth - actualDamage, 0);
+        if (currentHealth == 0)
+        {
+            animator.SetTrigger("Death");
+            callbacks.ForEach(c => c.OnDeath());
+            // TODO (Depending on the death animation) only destroy on round end so that corpses stay on the ground
+            // Destroy(gameObject);
+        }
+        else
+        {
+            animator.SetTrigger("Hurt");
+        }
+    }
+
+    protected FighterStats GetStats()
+    {
+        return StatsManager.instance.fighterStats[fighterType];
+    }
+
+    void OnTriggerEnter2D(Collider2D other)
+    {
+        if (other.CompareTag("AntiPlayer"))
+        {
+            var damageToDeal = Mathf.RoundToInt(baseAttackDamage * GetStats().damageMultiplier);
+            other.GetComponent<Fighter>().DealDamage(damageToDeal);
+        }
+    }
+
+}
diff --git a/Assets/Scripts/Fighter.cs.meta b/Assets/Scripts/Fighter.cs.meta
new file mode 100644
index 0000000000000000000000000000000000000000..e6b9012d8615f474908ed57403b7c6f94db0b64f
--- /dev/null
+++ b/Assets/Scripts/Fighter.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: b15d34b9baeff19448f00b406b4ff048
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Assets/Scripts/StatsManager.cs b/Assets/Scripts/StatsManager.cs
index ea985e2465f905d35fad488d07d6e669c5b40344..dc23221b67f2d53b24281164e1af48102dc0c183 100644
--- a/Assets/Scripts/StatsManager.cs
+++ b/Assets/Scripts/StatsManager.cs
@@ -11,14 +11,13 @@ public enum UpgradeTypes
     MANA_COST,
 }
 
-public struct EnemyStats
+public enum FighterTypes
 {
-    public float healthMultiplier;
-    public float damageMultiplier;
-    public float armorMultiplier;
+    ANTI_PLAYER,
+    ENEMY,
 }
 
-public struct PlayerStats
+public struct FighterStats
 {
     public float healthMultiplier;
     public float damageMultiplier;
@@ -53,26 +52,15 @@ public class StatsManager : MonoBehaviour
 
     public static StatsManager instance { get; private set; }
 
-    EnemyStats currentEnemyStats;
-    PlayerStats currentPlayerStats;
     [SerializeField] int currentMana;
-
     [SerializeField] List<Upgrade> availableUpgrades;
 
+    // The currently active statistics for each fighter type
+    public Dictionary<FighterTypes, FighterStats> fighterStats = new Dictionary<FighterTypes, FighterStats>();
+
     // Information about currently available and purchased upgrades. Should only be read, not modified.
     public Dictionary<UpgradeTypes, UpgradeData> upgrades = new Dictionary<UpgradeTypes, UpgradeData>();
 
-    public EnemyStats GetEnemyStats()
-    {
-        return currentEnemyStats;
-    }
-
-    public PlayerStats GetPlayerStats(int stage)
-    {
-        // TODO use `stage`
-        return currentPlayerStats;
-    }
-
     public int GetMana()
     {
         return currentMana;
@@ -120,9 +108,10 @@ public class StatsManager : MonoBehaviour
 
     void RecalculateStatMultipliers()
     {
-        currentEnemyStats.healthMultiplier = upgrades[UpgradeTypes.ENEMY_HEALTH].GetTotalEffectMultiplier();
-        currentEnemyStats.damageMultiplier = upgrades[UpgradeTypes.ENEMY_DAMAGE].GetTotalEffectMultiplier();
-        currentEnemyStats.armorMultiplier = upgrades[UpgradeTypes.ENEMY_ARMOR].GetTotalEffectMultiplier();
+        var enemyStats = fighterStats[FighterTypes.ENEMY];
+        enemyStats.healthMultiplier = upgrades[UpgradeTypes.ENEMY_HEALTH].GetTotalEffectMultiplier();
+        enemyStats.damageMultiplier = upgrades[UpgradeTypes.ENEMY_DAMAGE].GetTotalEffectMultiplier();
+        enemyStats.armorMultiplier = upgrades[UpgradeTypes.ENEMY_ARMOR].GetTotalEffectMultiplier();
     }
 
     void Awake()
@@ -143,11 +132,17 @@ public class StatsManager : MonoBehaviour
             upgrades.Add(upgrade.type, upgradeData);
         }
 
-        currentEnemyStats.healthMultiplier = 1f;
-        currentEnemyStats.damageMultiplier = 1f;
-        currentEnemyStats.armorMultiplier = 1f;
-        currentPlayerStats.healthMultiplier = 1f;
-        currentPlayerStats.damageMultiplier = 1f;
-        currentPlayerStats.armorMultiplier = 1f;
+        fighterStats.Add(FighterTypes.ANTI_PLAYER, new FighterStats()
+        {
+            healthMultiplier = 1f,
+            damageMultiplier = 1f,
+            armorMultiplier = 1f,
+        });
+        fighterStats.Add(FighterTypes.ENEMY, new FighterStats()
+        {
+            healthMultiplier = 1f,
+            damageMultiplier = 1f,
+            armorMultiplier = 1f,
+        });
     }
 }