diff --git a/fabric-item-api-v1/src/main/java/net/fabricmc/fabric/api/item/v1/FabricItem.java b/fabric-item-api-v1/src/main/java/net/fabricmc/fabric/api/item/v1/FabricItem.java
index e6f129f9b..5be9d9c3a 100644
--- a/fabric-item-api-v1/src/main/java/net/fabricmc/fabric/api/item/v1/FabricItem.java
+++ b/fabric-item-api-v1/src/main/java/net/fabricmc/fabric/api/item/v1/FabricItem.java
@@ -17,12 +17,14 @@
 package net.fabricmc.fabric.api.item.v1;
 
 import com.google.common.collect.Multimap;
+import org.jetbrains.annotations.Nullable;
 
 import net.minecraft.block.BlockState;
 import net.minecraft.entity.EquipmentSlot;
 import net.minecraft.entity.attribute.EntityAttribute;
 import net.minecraft.entity.attribute.EntityAttributeModifier;
 import net.minecraft.entity.player.PlayerEntity;
+import net.minecraft.item.FoodComponent;
 import net.minecraft.item.Item;
 import net.minecraft.item.ItemStack;
 import net.minecraft.util.Hand;
@@ -122,4 +124,15 @@ public interface FabricItem {
 	default ItemStack getRecipeRemainder(ItemStack stack) {
 		return ((Item) this).hasRecipeRemainder() ? ((Item) this).getRecipeRemainder().getDefaultStack() : ItemStack.EMPTY;
 	}
+
+	/**
+	 * This is a stack-aware version of {@link Item#getFoodComponent()}.
+	 * Note that simple food component can also be set via {@link Item.Settings#food(FoodComponent)}.
+	 * If you want to get a food component for a stack, is <strong>recommended</strong> to use the stack version of this method: {@link FabricItemStack#getFoodComponent()}.
+	 *
+	 * @return this item's {@link FoodComponent}, or {@code null} if none was set
+	 */
+	default @Nullable FoodComponent getFoodComponent(ItemStack stack) {
+		return ((Item) this).getFoodComponent();
+	}
 }
diff --git a/fabric-item-api-v1/src/main/java/net/fabricmc/fabric/api/item/v1/FabricItemStack.java b/fabric-item-api-v1/src/main/java/net/fabricmc/fabric/api/item/v1/FabricItemStack.java
index 0c646a6aa..4f1932ca0 100644
--- a/fabric-item-api-v1/src/main/java/net/fabricmc/fabric/api/item/v1/FabricItemStack.java
+++ b/fabric-item-api-v1/src/main/java/net/fabricmc/fabric/api/item/v1/FabricItemStack.java
@@ -16,6 +16,9 @@
 
 package net.fabricmc.fabric.api.item.v1;
 
+import org.jetbrains.annotations.Nullable;
+
+import net.minecraft.item.FoodComponent;
 import net.minecraft.item.Item;
 import net.minecraft.item.ItemStack;
 
@@ -36,4 +39,14 @@ public interface FabricItemStack {
 	default ItemStack getRecipeRemainder() {
 		return ((ItemStack) this).getItem().getRecipeRemainder((ItemStack) this);
 	}
+
+	/**
+	 * Stack-aware version of {@link Item#getFoodComponent()}.
+	 * See {@link FabricItem#getFoodComponent(ItemStack)} for a more in depth description.
+	 *
+	 * @return this item stack's {@link FoodComponent}, or {@code null} if none was set
+	 */
+	default @Nullable FoodComponent getFoodComponent() {
+		return ((ItemStack) this).getItem().getFoodComponent(((ItemStack) this));
+	}
 }
diff --git a/fabric-item-api-v1/src/main/java/net/fabricmc/fabric/mixin/item/BlockItemMixin.java b/fabric-item-api-v1/src/main/java/net/fabricmc/fabric/mixin/item/BlockItemMixin.java
new file mode 100644
index 000000000..bef3b5e09
--- /dev/null
+++ b/fabric-item-api-v1/src/main/java/net/fabricmc/fabric/mixin/item/BlockItemMixin.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2016, 2017, 2018, 2019 FabricMC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.fabricmc.fabric.mixin.item;
+
+import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.injection.At;
+import org.spongepowered.asm.mixin.injection.Redirect;
+
+import net.minecraft.item.BlockItem;
+import net.minecraft.item.ItemUsageContext;
+
+@Mixin(BlockItem.class)
+class BlockItemMixin {
+	@Redirect(method = "useOnBlock", at = @At(value = "INVOKE", target = "Lnet/minecraft/item/BlockItem;isFood()Z"))
+	private boolean isStackAwareFood(BlockItem instance, ItemUsageContext context) {
+		return context.getStack().isFood();
+	}
+}
diff --git a/fabric-item-api-v1/src/main/java/net/fabricmc/fabric/mixin/item/CatEntityMixin.java b/fabric-item-api-v1/src/main/java/net/fabricmc/fabric/mixin/item/CatEntityMixin.java
new file mode 100644
index 000000000..45040e85a
--- /dev/null
+++ b/fabric-item-api-v1/src/main/java/net/fabricmc/fabric/mixin/item/CatEntityMixin.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2016, 2017, 2018, 2019 FabricMC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.fabricmc.fabric.mixin.item;
+
+import org.jetbrains.annotations.Nullable;
+import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.injection.At;
+import org.spongepowered.asm.mixin.injection.Redirect;
+
+import net.minecraft.entity.passive.CatEntity;
+import net.minecraft.entity.player.PlayerEntity;
+import net.minecraft.item.FoodComponent;
+import net.minecraft.item.Item;
+import net.minecraft.util.Hand;
+
+@Mixin(CatEntity.class)
+class CatEntityMixin {
+	@Redirect(method = "interactMob", at = @At(value = "INVOKE", target = "Lnet/minecraft/item/Item;getFoodComponent()Lnet/minecraft/item/FoodComponent;"))
+	private @Nullable FoodComponent getStackAwareFoodComponent(Item instance, PlayerEntity player, Hand hand) {
+		return player.getStackInHand(hand).getFoodComponent();
+	}
+
+	@Redirect(method = "interactMob", at = @At(value = "INVOKE", target = "Lnet/minecraft/item/Item;isFood()Z"))
+	private boolean isStackAwareFood(Item instance, PlayerEntity player, Hand hand) {
+		return player.getStackInHand(hand).isFood();
+	}
+}
diff --git a/fabric-item-api-v1/src/main/java/net/fabricmc/fabric/mixin/item/CookingRecipeJsonBuilderMixin.java b/fabric-item-api-v1/src/main/java/net/fabricmc/fabric/mixin/item/CookingRecipeJsonBuilderMixin.java
new file mode 100644
index 000000000..ebb69882e
--- /dev/null
+++ b/fabric-item-api-v1/src/main/java/net/fabricmc/fabric/mixin/item/CookingRecipeJsonBuilderMixin.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2016, 2017, 2018, 2019 FabricMC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.fabricmc.fabric.mixin.item;
+
+import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.injection.At;
+import org.spongepowered.asm.mixin.injection.Redirect;
+
+import net.minecraft.data.server.recipe.CookingRecipeJsonBuilder;
+import net.minecraft.item.Item;
+
+@Mixin(CookingRecipeJsonBuilder.class)
+class CookingRecipeJsonBuilderMixin {
+	@Redirect(method = "getSmeltingRecipeCategory", at = @At(value = "INVOKE", target = "Lnet/minecraft/item/Item;isFood()Z"))
+	private static boolean isStackAwareFood(Item instance) {
+		return instance.getDefaultStack().isFood();
+	}
+}
diff --git a/fabric-item-api-v1/src/main/java/net/fabricmc/fabric/mixin/item/FoxEntityMixin.java b/fabric-item-api-v1/src/main/java/net/fabricmc/fabric/mixin/item/FoxEntityMixin.java
new file mode 100644
index 000000000..c8a7ea63e
--- /dev/null
+++ b/fabric-item-api-v1/src/main/java/net/fabricmc/fabric/mixin/item/FoxEntityMixin.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2016, 2017, 2018, 2019 FabricMC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.fabricmc.fabric.mixin.item;
+
+import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.injection.At;
+import org.spongepowered.asm.mixin.injection.Redirect;
+
+import net.minecraft.entity.EntityType;
+import net.minecraft.entity.EquipmentSlot;
+import net.minecraft.entity.passive.AnimalEntity;
+import net.minecraft.entity.passive.FoxEntity;
+import net.minecraft.item.Item;
+import net.minecraft.item.ItemStack;
+import net.minecraft.world.World;
+
+@Mixin(FoxEntity.class)
+abstract class FoxEntityMixin extends AnimalEntity {
+	protected FoxEntityMixin(EntityType<? extends AnimalEntity> entityType, World world) {
+		super(entityType, world);
+	}
+
+	@Redirect(method = {"canEat", "canPickupItem"}, at = @At(value = "INVOKE", target = "Lnet/minecraft/item/Item;isFood()Z", ordinal = 0))
+	private boolean isStackAwareFood(Item instance, ItemStack stack) {
+		return stack.isFood();
+	}
+
+	@Redirect(method = {"canPickupItem"}, at = @At(value = "INVOKE", target = "Lnet/minecraft/item/Item;isFood()Z", ordinal = 1))
+	private boolean isEquippedStackAwareFood(Item instance) {
+		return this.getEquippedStack(EquipmentSlot.MAINHAND).isFood();
+	}
+}
diff --git a/fabric-item-api-v1/src/main/java/net/fabricmc/fabric/mixin/item/HungerManagerMixin.java b/fabric-item-api-v1/src/main/java/net/fabricmc/fabric/mixin/item/HungerManagerMixin.java
new file mode 100644
index 000000000..39836fad3
--- /dev/null
+++ b/fabric-item-api-v1/src/main/java/net/fabricmc/fabric/mixin/item/HungerManagerMixin.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2016, 2017, 2018, 2019 FabricMC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.fabricmc.fabric.mixin.item;
+
+import org.jetbrains.annotations.Nullable;
+import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.injection.At;
+import org.spongepowered.asm.mixin.injection.Redirect;
+
+import net.minecraft.entity.player.HungerManager;
+import net.minecraft.item.FoodComponent;
+import net.minecraft.item.Item;
+import net.minecraft.item.ItemStack;
+
+@Mixin(HungerManager.class)
+class HungerManagerMixin {
+	@Redirect(method = "eat", at = @At(value = "INVOKE", target = "Lnet/minecraft/item/Item;getFoodComponent()Lnet/minecraft/item/FoodComponent;"))
+	private @Nullable FoodComponent getStackAwareFoodComponent(Item instance, Item item, ItemStack stack) {
+		return stack.getFoodComponent();
+	}
+
+	@Redirect(method = "eat", at = @At(value = "INVOKE", target = "Lnet/minecraft/item/Item;isFood()Z"))
+	private boolean isStackAwareFood(Item instance, Item item, ItemStack stack) {
+		return stack.isFood();
+	}
+}
diff --git a/fabric-item-api-v1/src/main/java/net/fabricmc/fabric/mixin/item/ItemMixin.java b/fabric-item-api-v1/src/main/java/net/fabricmc/fabric/mixin/item/ItemMixin.java
index 8214295ee..8d18b0b43 100644
--- a/fabric-item-api-v1/src/main/java/net/fabricmc/fabric/mixin/item/ItemMixin.java
+++ b/fabric-item-api-v1/src/main/java/net/fabricmc/fabric/mixin/item/ItemMixin.java
@@ -21,9 +21,16 @@ import org.spongepowered.asm.mixin.Mixin;
 import org.spongepowered.asm.mixin.Unique;
 import org.spongepowered.asm.mixin.injection.At;
 import org.spongepowered.asm.mixin.injection.Inject;
+import org.spongepowered.asm.mixin.injection.Redirect;
 import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
 
+import net.minecraft.entity.LivingEntity;
+import net.minecraft.entity.player.PlayerEntity;
+import net.minecraft.item.FoodComponent;
 import net.minecraft.item.Item;
+import net.minecraft.item.ItemStack;
+import net.minecraft.util.Hand;
+import net.minecraft.world.World;
 
 import net.fabricmc.fabric.api.item.v1.CustomDamageHandler;
 import net.fabricmc.fabric.api.item.v1.EquipmentSlotProvider;
@@ -67,4 +74,29 @@ abstract class ItemMixin implements ItemExtensions, FabricItem {
 	public void fabric_setCustomDamageHandler(@Nullable CustomDamageHandler handler) {
 		this.customDamageHandler = handler;
 	}
+
+	@Redirect(method = "use", at = @At(value = "INVOKE", target = "Lnet/minecraft/item/Item;getFoodComponent()Lnet/minecraft/item/FoodComponent;"))
+	private @Nullable FoodComponent getStackAwareFoodComponent(Item instance, World world, PlayerEntity user, Hand hand) {
+		return user.getStackInHand(hand).getFoodComponent();
+	}
+
+	@Redirect(method = "getMaxUseTime", at = @At(value = "INVOKE", target = "Lnet/minecraft/item/Item;getFoodComponent()Lnet/minecraft/item/FoodComponent;"))
+	private @Nullable FoodComponent getStackAwareFoodComponent(Item instance, ItemStack stack) {
+		return stack.getFoodComponent();
+	}
+
+	@Redirect(method = {"getMaxUseTime", "getUseAction"}, at = @At(value = "INVOKE", target = "Lnet/minecraft/item/Item;isFood()Z"))
+	private boolean isStackAwareFood(Item instance, ItemStack stack) {
+		return stack.isFood();
+	}
+
+	@Redirect(method = "use", at = @At(value = "INVOKE", target = "Lnet/minecraft/item/Item;isFood()Z"))
+	private boolean isStackAwareFood(Item instance, World world, PlayerEntity user, Hand hand) {
+		return user.getStackInHand(hand).isFood();
+	}
+
+	@Redirect(method = "finishUsing", at = @At(value = "INVOKE", target = "Lnet/minecraft/item/Item;isFood()Z"))
+	private boolean isStackAwareFood(Item instance, ItemStack stack, World world, LivingEntity user) {
+		return stack.isFood();
+	}
 }
diff --git a/fabric-item-api-v1/src/main/java/net/fabricmc/fabric/mixin/item/ItemStackMixin.java b/fabric-item-api-v1/src/main/java/net/fabricmc/fabric/mixin/item/ItemStackMixin.java
index 89df9b5c8..bc09338c6 100644
--- a/fabric-item-api-v1/src/main/java/net/fabricmc/fabric/mixin/item/ItemStackMixin.java
+++ b/fabric-item-api-v1/src/main/java/net/fabricmc/fabric/mixin/item/ItemStackMixin.java
@@ -28,6 +28,7 @@ import org.spongepowered.asm.mixin.injection.Inject;
 import org.spongepowered.asm.mixin.injection.ModifyArg;
 import org.spongepowered.asm.mixin.injection.Redirect;
 import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
+import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
 
 import net.minecraft.block.BlockState;
 import net.minecraft.entity.EquipmentSlot;
@@ -100,4 +101,9 @@ public abstract class ItemStackMixin implements FabricItemStack {
 	public boolean hookIsSuitableFor(Item item, BlockState state) {
 		return item.isSuitableFor((ItemStack) (Object) this, state);
 	}
+
+	@Inject(method = "isFood", at = @At("HEAD"), cancellable = true)
+	public void isStackAwareFood(CallbackInfoReturnable<Boolean> cir) {
+		cir.setReturnValue(this.getFoodComponent() != null);
+	}
 }
diff --git a/fabric-item-api-v1/src/main/java/net/fabricmc/fabric/mixin/item/LivingEntityMixin.java b/fabric-item-api-v1/src/main/java/net/fabricmc/fabric/mixin/item/LivingEntityMixin.java
index d147509d4..920468203 100644
--- a/fabric-item-api-v1/src/main/java/net/fabricmc/fabric/mixin/item/LivingEntityMixin.java
+++ b/fabric-item-api-v1/src/main/java/net/fabricmc/fabric/mixin/item/LivingEntityMixin.java
@@ -16,20 +16,29 @@
 
 package net.fabricmc.fabric.mixin.item;
 
+import org.jetbrains.annotations.Nullable;
 import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.Shadow;
 import org.spongepowered.asm.mixin.injection.At;
 import org.spongepowered.asm.mixin.injection.Inject;
+import org.spongepowered.asm.mixin.injection.Redirect;
 import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
 
 import net.minecraft.entity.EquipmentSlot;
 import net.minecraft.entity.LivingEntity;
+import net.minecraft.item.FoodComponent;
+import net.minecraft.item.Item;
 import net.minecraft.item.ItemStack;
+import net.minecraft.world.World;
 
 import net.fabricmc.fabric.api.item.v1.EquipmentSlotProvider;
 import net.fabricmc.fabric.impl.item.ItemExtensions;
 
 @Mixin(LivingEntity.class)
 abstract class LivingEntityMixin {
+	@Shadow
+	protected ItemStack activeItemStack;
+
 	@Inject(method = "getPreferredEquipmentSlot", at = @At(value = "HEAD"), cancellable = true)
 	private static void onGetPreferredEquipmentSlot(ItemStack stack, CallbackInfoReturnable<EquipmentSlot> info) {
 		EquipmentSlotProvider equipmentSlotProvider = ((ItemExtensions) stack.getItem()).fabric_getEquipmentSlotProvider();
@@ -38,4 +47,19 @@ abstract class LivingEntityMixin {
 			info.setReturnValue(equipmentSlotProvider.getPreferredEquipmentSlot(stack));
 		}
 	}
+
+	@Redirect(method = "shouldSpawnConsumptionEffects", at = @At(value = "INVOKE", target = "Lnet/minecraft/item/Item;getFoodComponent()Lnet/minecraft/item/FoodComponent;"))
+	private @Nullable FoodComponent getStackAwareFoodComponent(Item instance) {
+		return this.activeItemStack.getFoodComponent();
+	}
+
+	@Redirect(method = "applyFoodEffects", at = @At(value = "INVOKE", target = "Lnet/minecraft/item/Item;getFoodComponent()Lnet/minecraft/item/FoodComponent;"))
+	private @Nullable FoodComponent getStackAwareFoodComponent(Item instance, ItemStack stack, World world, LivingEntity targetEntity) {
+		return stack.getFoodComponent();
+	}
+
+	@Redirect(method = "applyFoodEffects", at = @At(value = "INVOKE", target = "Lnet/minecraft/item/Item;isFood()Z"))
+	private boolean isStackAwareFood(Item instance, ItemStack stack, World world, LivingEntity targetEntity) {
+		return stack.isFood();
+	}
 }
diff --git a/fabric-item-api-v1/src/main/java/net/fabricmc/fabric/mixin/item/WolfEntityMixin.java b/fabric-item-api-v1/src/main/java/net/fabricmc/fabric/mixin/item/WolfEntityMixin.java
new file mode 100644
index 000000000..ff75a048e
--- /dev/null
+++ b/fabric-item-api-v1/src/main/java/net/fabricmc/fabric/mixin/item/WolfEntityMixin.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2016, 2017, 2018, 2019 FabricMC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.fabricmc.fabric.mixin.item;
+
+import com.llamalad7.mixinextras.sugar.Share;
+import com.llamalad7.mixinextras.sugar.ref.LocalRef;
+import org.jetbrains.annotations.Nullable;
+import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.injection.At;
+import org.spongepowered.asm.mixin.injection.Inject;
+import org.spongepowered.asm.mixin.injection.Redirect;
+import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
+
+import net.minecraft.entity.passive.WolfEntity;
+import net.minecraft.entity.player.PlayerEntity;
+import net.minecraft.item.FoodComponent;
+import net.minecraft.item.Item;
+import net.minecraft.item.ItemStack;
+import net.minecraft.util.ActionResult;
+import net.minecraft.util.Hand;
+
+@Mixin(WolfEntity.class)
+class WolfEntityMixin {
+	@Inject(method = "interactMob", at = @At("HEAD"))
+	private void storeCopy(PlayerEntity player, Hand hand, CallbackInfoReturnable<ActionResult> cir, @Share("interaction_stack") LocalRef<ItemStack> stackRef) {
+		stackRef.set(player.getStackInHand(hand).copy());
+	}
+
+	@Redirect(method = "interactMob", at = @At(value = "INVOKE", target = "Lnet/minecraft/item/Item;getFoodComponent()Lnet/minecraft/item/FoodComponent;"))
+	private @Nullable FoodComponent getStackAwareFoodComponent(Item instance, PlayerEntity player, Hand hand, @Share("interaction_stack") LocalRef<ItemStack> stackRef) {
+		return stackRef.get().getFoodComponent();
+	}
+
+	@Redirect(method = "isBreedingItem", at = @At(value = "INVOKE", target = "Lnet/minecraft/item/Item;getFoodComponent()Lnet/minecraft/item/FoodComponent;"))
+	private @Nullable FoodComponent getStackAwareFoodComponent(Item instance, ItemStack stack) {
+		return stack.getFoodComponent();
+	}
+
+	@Redirect(method = "isBreedingItem", at = @At(value = "INVOKE", target = "Lnet/minecraft/item/Item;isFood()Z", ordinal = 0))
+	private boolean isStackAwareFood(Item instance, ItemStack stack) {
+		return stack.isFood();
+	}
+}
diff --git a/fabric-item-api-v1/src/main/resources/fabric-item-api-v1.mixins.json b/fabric-item-api-v1/src/main/resources/fabric-item-api-v1.mixins.json
index ef5c4b4b4..f762ae7b1 100644
--- a/fabric-item-api-v1/src/main/resources/fabric-item-api-v1.mixins.json
+++ b/fabric-item-api-v1/src/main/resources/fabric-item-api-v1.mixins.json
@@ -5,11 +5,17 @@
   "mixins": [
     "AbstractFurnaceBlockEntityMixin",
     "ArmorItemMixin",
+    "BlockItemMixin",
     "BrewingStandBlockEntityMixin",
+    "CatEntityMixin",
+    "CookingRecipeJsonBuilderMixin",
+    "FoxEntityMixin",
+    "HungerManagerMixin",
     "ItemMixin",
     "ItemStackMixin",
     "LivingEntityMixin",
-    "RecipeMixin"
+    "RecipeMixin",
+    "WolfEntityMixin"
   ],
   "injectors": {
     "defaultRequire": 1
diff --git a/fabric-item-api-v1/src/testmod/java/net/fabricmc/fabric/test/item/FoodGameInitializer.java b/fabric-item-api-v1/src/testmod/java/net/fabricmc/fabric/test/item/FoodGameInitializer.java
new file mode 100644
index 000000000..4d58c04de
--- /dev/null
+++ b/fabric-item-api-v1/src/testmod/java/net/fabricmc/fabric/test/item/FoodGameInitializer.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2016, 2017, 2018, 2019 FabricMC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.fabricmc.fabric.test.item;
+
+import org.jetbrains.annotations.Nullable;
+
+import net.minecraft.item.FoodComponent;
+import net.minecraft.item.Item;
+import net.minecraft.item.ItemStack;
+import net.minecraft.registry.Registries;
+import net.minecraft.registry.Registry;
+import net.minecraft.util.Identifier;
+
+import net.fabricmc.api.ModInitializer;
+import net.fabricmc.fabric.api.item.v1.FabricItemSettings;
+
+public final class FoodGameInitializer implements ModInitializer {
+	public static final Item DAMAGE = Registry.register(Registries.ITEM, new Identifier("fabric-item-api-v1-testmod", "damage_food"), new DamageFood(new FabricItemSettings().maxDamage(20)));
+	public static final Item NAME = Registry.register(Registries.ITEM, new Identifier("fabric-item-api-v1-testmod", "name_food"), new NameFood(new FabricItemSettings()));
+
+	@Override
+	public void onInitialize() {
+	}
+
+	public static class DamageFood extends Item {
+		public DamageFood(Settings settings) {
+			super(settings);
+		}
+
+		@Override
+		public @Nullable FoodComponent getFoodComponent(ItemStack stack) {
+			return new FoodComponent.Builder()
+					.hunger(20 - 20 * stack.getDamage() / stack.getMaxDamage())
+					.saturationModifier(0.5f)
+					.build();
+		}
+	}
+
+	public static class NameFood extends Item {
+		public NameFood(Settings settings) {
+			super(settings);
+		}
+
+		@Override
+		public @Nullable FoodComponent getFoodComponent(ItemStack stack) {
+			return Registries.ITEM.get(new Identifier(stack.getName().getString())).getFoodComponent(stack);
+		}
+	}
+}
diff --git a/fabric-item-api-v1/src/testmod/java/net/fabricmc/fabric/test/item/gametest/FoodGameTest.java b/fabric-item-api-v1/src/testmod/java/net/fabricmc/fabric/test/item/gametest/FoodGameTest.java
new file mode 100644
index 000000000..16938db7d
--- /dev/null
+++ b/fabric-item-api-v1/src/testmod/java/net/fabricmc/fabric/test/item/gametest/FoodGameTest.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2016, 2017, 2018, 2019 FabricMC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.fabricmc.fabric.test.item.gametest;
+
+import java.util.Objects;
+
+import net.minecraft.entity.EntityType;
+import net.minecraft.entity.passive.WolfEntity;
+import net.minecraft.entity.player.HungerManager;
+import net.minecraft.entity.player.PlayerEntity;
+import net.minecraft.item.FoodComponent;
+import net.minecraft.item.FoodComponents;
+import net.minecraft.item.ItemStack;
+import net.minecraft.test.GameTest;
+import net.minecraft.test.TestContext;
+import net.minecraft.text.Text;
+import net.minecraft.util.Hand;
+import net.minecraft.util.math.Vec3d;
+
+import net.fabricmc.fabric.api.gametest.v1.FabricGameTest;
+import net.fabricmc.fabric.test.item.FoodGameInitializer;
+
+public final class FoodGameTest implements FabricGameTest {
+	@GameTest(templateName = EMPTY_STRUCTURE)
+	public void damageFoodTest(TestContext context) {
+		PlayerEntity player = context.createMockSurvivalPlayer();
+		HungerManager hungerManager = player.getHungerManager();
+
+		for (int damage : new int[]{0, 1, 10, 19}) {
+			hungerManager.setFoodLevel(0);
+			hungerManager.setSaturationLevel(0);
+			ItemStack foodStack = FoodGameInitializer.DAMAGE.getDefaultStack();
+			foodStack.setDamage(damage);
+			player.eatFood(player.getWorld(), foodStack.copy());
+			FoodComponent fc = Objects.requireNonNull(foodStack.getFoodComponent());
+			int foodActual = hungerManager.getFoodLevel();
+			int foodExpect = Math.min(20, fc.getHunger());
+			context.assertTrue(foodActual == foodExpect, "damage=%d, food actual %d, expect %d".formatted(damage, foodActual, foodExpect));
+			float satActual = hungerManager.getSaturationLevel();
+			float satExpect = Math.min(foodExpect, fc.getHunger() * fc.getSaturationModifier() * 2);
+			context.assertTrue(satActual == satExpect, "damage=%d, sat actual %f, expect %f".formatted(damage, satActual, satExpect));
+		}
+
+		context.complete();
+	}
+
+	@GameTest(templateName = EMPTY_STRUCTURE)
+	public void nameFoodTest(TestContext context) {
+		PlayerEntity player = context.createMockSurvivalPlayer();
+		HungerManager hungerManager = player.getHungerManager();
+		hungerManager.setFoodLevel(0);
+		hungerManager.setSaturationLevel(0);
+		ItemStack foodStack = FoodGameInitializer.NAME.getDefaultStack();
+		foodStack.setCustomName(Text.literal("enchanted_golden_apple"));
+		player.eatFood(player.getWorld(), foodStack.copy());
+		FoodComponent fc = FoodComponents.ENCHANTED_GOLDEN_APPLE;
+		int foodActual = hungerManager.getFoodLevel();
+		int foodExpect = Math.min(20, fc.getHunger());
+		context.assertTrue(foodActual == foodExpect, "enchanted_golden_apple, food actual %d, expect %d".formatted(foodActual, foodExpect));
+		float satActual = hungerManager.getSaturationLevel();
+		float satExpect = Math.min(foodExpect, fc.getHunger() * fc.getSaturationModifier() * 2);
+		context.assertTrue(satActual == satExpect, "enchanted_golden_apple, sat actual %f, expect %f".formatted(satActual, satExpect));
+		context.complete();
+	}
+
+	@GameTest(templateName = EMPTY_STRUCTURE)
+	public void nameMeatTest(TestContext context) {
+		PlayerEntity player = context.createMockSurvivalPlayer();
+		WolfEntity wolf = context.spawnEntity(EntityType.WOLF, context.getRelative(Vec3d.ZERO));
+		wolf.setTamed(true);
+		wolf.setOwner(player);
+		wolf.setHealth(1f);
+		ItemStack meat = FoodGameInitializer.NAME.getDefaultStack();
+		meat.setCustomName(Text.of("mutton"));
+		player.setStackInHand(Hand.MAIN_HAND, meat);
+		player.interact(wolf, Hand.MAIN_HAND);
+		float wolfHealth = wolf.getHealth();
+		context.assertTrue(wolfHealth > 0, "actual %f, expect > 0".formatted(wolfHealth));
+		context.complete();
+	}
+}
diff --git a/fabric-item-api-v1/src/testmod/resources/assets/fabric-item-api-v1-testmod/models/item/damage_food.json b/fabric-item-api-v1/src/testmod/resources/assets/fabric-item-api-v1-testmod/models/item/damage_food.json
new file mode 100644
index 000000000..a25409877
--- /dev/null
+++ b/fabric-item-api-v1/src/testmod/resources/assets/fabric-item-api-v1-testmod/models/item/damage_food.json
@@ -0,0 +1,3 @@
+{
+  "parent": "minecraft:item/wooden_pickaxe"
+}
diff --git a/fabric-item-api-v1/src/testmod/resources/assets/fabric-item-api-v1-testmod/models/item/name_food.json b/fabric-item-api-v1/src/testmod/resources/assets/fabric-item-api-v1-testmod/models/item/name_food.json
new file mode 100644
index 000000000..70e896e70
--- /dev/null
+++ b/fabric-item-api-v1/src/testmod/resources/assets/fabric-item-api-v1-testmod/models/item/name_food.json
@@ -0,0 +1,3 @@
+{
+  "parent": "minecraft:item/book"
+}
diff --git a/fabric-item-api-v1/src/testmod/resources/fabric.mod.json b/fabric-item-api-v1/src/testmod/resources/fabric.mod.json
index 56e2f60a6..627b04606 100644
--- a/fabric-item-api-v1/src/testmod/resources/fabric.mod.json
+++ b/fabric-item-api-v1/src/testmod/resources/fabric.mod.json
@@ -14,7 +14,8 @@
       "net.fabricmc.fabric.test.item.FabricItemSettingsTests",
       "net.fabricmc.fabric.test.item.ItemUpdateAnimationTest",
       "net.fabricmc.fabric.test.item.ModifyItemAttributeModifiersCallbackTest",
-      "net.fabricmc.fabric.test.item.ArmorKnockbackResistanceTest"
+      "net.fabricmc.fabric.test.item.ArmorKnockbackResistanceTest",
+      "net.fabricmc.fabric.test.item.FoodGameInitializer"
     ],
     "client": [
       "net.fabricmc.fabric.test.item.client.TooltipTests"
@@ -22,7 +23,8 @@
     "fabric-gametest" : [
       "net.fabricmc.fabric.test.item.gametest.BrewingStandGameTest",
       "net.fabricmc.fabric.test.item.gametest.FurnaceGameTest",
-      "net.fabricmc.fabric.test.item.gametest.RecipeGameTest"
+      "net.fabricmc.fabric.test.item.gametest.RecipeGameTest",
+      "net.fabricmc.fabric.test.item.gametest.FoodGameTest"
     ]
   },
   "mixins": [