diff --git a/Content.Shared/Trigger/Components/Triggers/TriggerOnGotInsertedIntoContainerComponent.cs b/Content.Shared/Trigger/Components/Triggers/TriggerOnGotInsertedIntoContainerComponent.cs
new file mode 100644
index 0000000000..132167a747
--- /dev/null
+++ b/Content.Shared/Trigger/Components/Triggers/TriggerOnGotInsertedIntoContainerComponent.cs
@@ -0,0 +1,18 @@
+using Robust.Shared.GameStates;
+
+namespace Content.Shared.Trigger.Components.Triggers;
+
+///
+/// Triggers an entity when it gets inserted into a container.
+/// The user is the owner of the container the entity is being inserted into.
+///
+[RegisterComponent, NetworkedComponent, AutoGenerateComponentState]
+public sealed partial class TriggerOnGotInsertedIntoContainerComponent : BaseTriggerOnXComponent
+{
+ ///
+ /// The container to the entity has to be inserted into.
+ /// Null will allow all containers.
+ ///
+ [DataField, AutoNetworkedField]
+ public string? ContainerId;
+}
diff --git a/Content.Shared/Trigger/Components/Triggers/TriggerOnGotRemovedFromContainerComponent.cs b/Content.Shared/Trigger/Components/Triggers/TriggerOnGotRemovedFromContainerComponent.cs
new file mode 100644
index 0000000000..8c66bf4e81
--- /dev/null
+++ b/Content.Shared/Trigger/Components/Triggers/TriggerOnGotRemovedFromContainerComponent.cs
@@ -0,0 +1,18 @@
+using Robust.Shared.GameStates;
+
+namespace Content.Shared.Trigger.Components.Triggers;
+
+///
+/// Triggers an entity when it gets removed from a container.
+/// The user is the owner of the container the entity is being removed from.
+///
+[RegisterComponent, NetworkedComponent, AutoGenerateComponentState]
+public sealed partial class TriggerOnGotRemovedFromContainerComponent : BaseTriggerOnXComponent
+{
+ ///
+ /// The container to the entity has to be removed from.
+ /// Null will allow all containers.
+ ///
+ [DataField, AutoNetworkedField]
+ public string? ContainerId;
+}
diff --git a/Content.Shared/Trigger/Components/Triggers/TriggerOnInsertedIntoContainerComponent.cs b/Content.Shared/Trigger/Components/Triggers/TriggerOnInsertedIntoContainerComponent.cs
new file mode 100644
index 0000000000..d5616dfd85
--- /dev/null
+++ b/Content.Shared/Trigger/Components/Triggers/TriggerOnInsertedIntoContainerComponent.cs
@@ -0,0 +1,18 @@
+using Robust.Shared.GameStates;
+
+namespace Content.Shared.Trigger.Components.Triggers;
+
+///
+/// Triggers an entity when something is inserted into it.
+/// The user is the entity being inserted into the container.
+///
+[RegisterComponent, NetworkedComponent, AutoGenerateComponentState]
+public sealed partial class TriggerOnInsertedIntoContainerComponent : BaseTriggerOnXComponent
+{
+ ///
+ /// The container to the entity has to be inserted into.
+ /// Null will allow all containers.
+ ///
+ [DataField, AutoNetworkedField]
+ public string? ContainerId;
+}
diff --git a/Content.Shared/Trigger/Components/Triggers/TriggerOnRemovedFromContainerComponent.cs b/Content.Shared/Trigger/Components/Triggers/TriggerOnRemovedFromContainerComponent.cs
new file mode 100644
index 0000000000..095b040834
--- /dev/null
+++ b/Content.Shared/Trigger/Components/Triggers/TriggerOnRemovedFromContainerComponent.cs
@@ -0,0 +1,18 @@
+using Robust.Shared.GameStates;
+
+namespace Content.Shared.Trigger.Components.Triggers;
+
+///
+/// Triggers an entity when something is removed from it.
+/// The user is the entity being removed from the container.
+///
+[RegisterComponent, NetworkedComponent, AutoGenerateComponentState]
+public sealed partial class TriggerOnRemovedFromContainerComponent : BaseTriggerOnXComponent
+{
+ ///
+ /// The container to the entity has to be removed from.
+ /// Null will allow all containers.
+ ///
+ [DataField, AutoNetworkedField]
+ public string? ContainerId;
+}
diff --git a/Content.Shared/Trigger/Systems/TriggerOnContainerInteractionSystem.cs b/Content.Shared/Trigger/Systems/TriggerOnContainerInteractionSystem.cs
new file mode 100644
index 0000000000..8fa9308f70
--- /dev/null
+++ b/Content.Shared/Trigger/Systems/TriggerOnContainerInteractionSystem.cs
@@ -0,0 +1,70 @@
+using Content.Shared.Trigger.Components.Triggers;
+using Robust.Shared.Containers;
+using Robust.Shared.Timing;
+
+namespace Content.Shared.Trigger.Systems;
+
+///
+/// System for creating triggers when entities are inserted into or removed from containers.
+///
+public sealed class TriggerOnContainerInteractionSystem : EntitySystem
+{
+ [Dependency] private readonly TriggerSystem _trigger = default!;
+ [Dependency] private readonly IGameTiming _timing = default!;
+
+ public override void Initialize()
+ {
+ base.Initialize();
+
+ SubscribeLocalEvent(OnInsertedIntoContainer);
+ SubscribeLocalEvent(OnRemovedFromContainer);
+ SubscribeLocalEvent(OnGotInsertedIntoContainer);
+ SubscribeLocalEvent(OnGotRemovedFromContainer);
+ }
+
+ // Used by containers to trigger when entities are inserted into or removed from them
+ private void OnInsertedIntoContainer(Entity ent, ref EntInsertedIntoContainerMessage args)
+ {
+ if (_timing.ApplyingState)
+ return;
+
+ if (ent.Comp.ContainerId != null && ent.Comp.ContainerId != args.Container.ID)
+ return;
+
+ _trigger.Trigger(ent.Owner, args.Entity, ent.Comp.KeyOut);
+ }
+
+ private void OnRemovedFromContainer(Entity ent, ref EntRemovedFromContainerMessage args)
+ {
+ if (_timing.ApplyingState)
+ return;
+
+ if (ent.Comp.ContainerId != null && ent.Comp.ContainerId != args.Container.ID)
+ return;
+
+ _trigger.Trigger(ent.Owner, args.Entity, ent.Comp.KeyOut);
+ }
+
+ // Used by entities to trigger when they are inserted into or removed from a container
+ private void OnGotInsertedIntoContainer(Entity ent, ref EntGotInsertedIntoContainerMessage args)
+ {
+ if (_timing.ApplyingState)
+ return;
+
+ if (ent.Comp.ContainerId != null && ent.Comp.ContainerId != args.Container.ID)
+ return;
+
+ _trigger.Trigger(ent.Owner, args.Container.Owner, ent.Comp.KeyOut);
+ }
+
+ private void OnGotRemovedFromContainer(Entity ent, ref EntGotRemovedFromContainerMessage args)
+ {
+ if (_timing.ApplyingState)
+ return;
+
+ if (ent.Comp.ContainerId != null && ent.Comp.ContainerId != args.Container.ID)
+ return;
+
+ _trigger.Trigger(ent.Owner, args.Container.Owner, ent.Comp.KeyOut);
+ }
+}