diff --git a/CHANGELOG.rst b/CHANGELOG.rst
index 6d939d1a..4d35ddd0 100644
--- a/CHANGELOG.rst
+++ b/CHANGELOG.rst
@@ -18,6 +18,21 @@ __________
 
 
 
+[9.14.0] - 2024-09-12
+---------------------
+
+Added
+~~~~~
+
+* Adds event ``CONTENT_OBJECT_ASSOCIATIONS_CHANGED``
+* Adds ``ContentObjectChangedData``, which inherits from ContentObjectData and adds an optional list of string ``changes``.
+
+Deprecated
+~~~~~~~~~~
+
+* Deprecated event ``CONTENT_OBJECT_TAGS_CHANGED`` in favor of ``CONTENT_OBJECT_ASSOCIATIONS_CHANGED``
+  Plan to remove after Sumac.
+
 [9.13.0] - 2024-09-05
 ---------------------
 
diff --git a/openedx_events/__init__.py b/openedx_events/__init__.py
index 445806a0..40b95950 100644
--- a/openedx_events/__init__.py
+++ b/openedx_events/__init__.py
@@ -5,4 +5,4 @@
 more information about the project.
 """
 
-__version__ = "9.13.0"
+__version__ = "9.14.0"
diff --git a/openedx_events/content_authoring/data.py b/openedx_events/content_authoring/data.py
index e55cc871..4e76bcd7 100644
--- a/openedx_events/content_authoring/data.py
+++ b/openedx_events/content_authoring/data.py
@@ -185,7 +185,7 @@ class LibraryBlockData:
 @attr.s(frozen=True)
 class ContentObjectData:
     """
-    Data about changed content object.
+    Data about a content object.
 
     Arguments:
         object_id (str): identifier of the Content object. This represents the id of the course or library block
@@ -196,6 +196,23 @@ class ContentObjectData:
     object_id = attr.ib(type=str)
 
 
+@attr.s(frozen=True)
+class ContentObjectChangedData(ContentObjectData):
+    """
+    Data about a changed content object.
+
+    Arguments:
+        object_id (str): identifier of the Content object. This represents the id of the course or library block
+        as a string. For example:
+        block-v1:SampleTaxonomyOrg2+STC1+2023_1+type@vertical+block@f8de78f0897049ce997777a3a31b6ea0
+
+        changes: list of changes made to this ContentObject, e.g. "tags", "collections"
+        If list is empty, assume everything has changed.
+    """
+
+    changes = attr.ib(type=List[str], factory=list)
+
+
 @attr.s(frozen=True)
 class LibraryCollectionData:
     """
diff --git a/openedx_events/content_authoring/signals.py b/openedx_events/content_authoring/signals.py
index 2b00ea15..664c4ed1 100644
--- a/openedx_events/content_authoring/signals.py
+++ b/openedx_events/content_authoring/signals.py
@@ -10,6 +10,7 @@
 from openedx_events.content_authoring.data import (
     CertificateConfigData,
     ContentLibraryData,
+    ContentObjectChangedData,
     ContentObjectData,
     CourseCatalogData,
     CourseData,
@@ -201,9 +202,21 @@
     }
 )
 
+# .. event_type: org.openedx.content_authoring.content.object.associations.changed.v1
+# .. event_name: CONTENT_OBJECT_ASSOCIATIONS_CHANGED
+# .. event_description: emitted when an object's associations are changed, e.g tags, collections
+# .. event_data: ContentObjectData
+CONTENT_OBJECT_ASSOCIATIONS_CHANGED = OpenEdxPublicSignal(
+    event_type="org.openedx.content_authoring.content.object.associations.changed.v1",
+    data={
+        "content_object": ContentObjectChangedData
+    }
+)
+
 # .. event_type: org.openedx.content_authoring.content.object.tags.changed.v1
 # .. event_name: CONTENT_OBJECT_TAGS_CHANGED
 # .. event_description: emitted when an object's tags are changed
+#    DEPRECATED: please use CONTENT_OBJECT_ASSOCIATIONS_CHANGED instead.
 # .. event_data: ContentObjectData
 CONTENT_OBJECT_TAGS_CHANGED = OpenEdxPublicSignal(
     event_type="org.openedx.content_authoring.content.object.tags.changed.v1",
diff --git a/openedx_events/event_bus/avro/tests/schemas/org+openedx+content_authoring+content+object+associations+changed+v1_schema.avsc b/openedx_events/event_bus/avro/tests/schemas/org+openedx+content_authoring+content+object+associations+changed+v1_schema.avsc
new file mode 100644
index 00000000..5f3cfb2c
--- /dev/null
+++ b/openedx_events/event_bus/avro/tests/schemas/org+openedx+content_authoring+content+object+associations+changed+v1_schema.avsc
@@ -0,0 +1,28 @@
+{
+  "name": "CloudEvent",
+  "type": "record",
+  "doc": "Avro Event Format for CloudEvents created with openedx_events/schema",
+  "fields": [
+    {
+      "name": "content_object",
+      "type": {
+        "name": "ContentObjectChangedData",
+        "type": "record",
+        "fields": [
+          {
+            "name": "object_id",
+            "type": "string"
+          },
+          {
+            "name": "changes",
+            "type": {
+              "type": "array",
+              "items": "string"
+            }
+          }
+        ]
+      }
+    }
+  ],
+  "namespace": "org.openedx.content_authoring.content.object.associations.changed.v1"
+}
\ No newline at end of file
diff --git a/openedx_events/event_bus/avro/tests/test_avro.py b/openedx_events/event_bus/avro/tests/test_avro.py
index 4d564b27..87634067 100644
--- a/openedx_events/event_bus/avro/tests/test_avro.py
+++ b/openedx_events/event_bus/avro/tests/test_avro.py
@@ -108,6 +108,7 @@ def generate_test_event_data_for_data_type(data_type):  # pragma: no cover
         LibraryLocatorV2: LibraryLocatorV2.from_string('lib:MITx:reallyhardproblems'),
         LibraryUsageLocatorV2: LibraryUsageLocatorV2.from_string('lb:MITx:reallyhardproblems:problem:problem1'),
         List[int]: [1, 2, 3],
+        List[str]: ["hi", "there"],
         datetime: datetime.now(),
         CCXLocator: CCXLocator(org='edx', course='DemoX', run='Demo_course', ccx='1'),
         UUID: uuid4(),