diff --git a/opentech/apply/activity/messaging.py b/opentech/apply/activity/messaging.py
index c0ceeea24868c5e1191c711de847e312543d7bac..0310a560f0a9b3078d01e85e650579e9c74c4dc3 100644
--- a/opentech/apply/activity/messaging.py
+++ b/opentech/apply/activity/messaging.py
@@ -12,6 +12,11 @@ def link_to(target, request):
     return request.scheme + '://' + request.get_host() + target.get_absolute_url()
 
 
+neat_related = {
+    MESSAGES.DETERMINATION_OUTCOME: 'determination',
+}
+
+
 class AdapterBase:
     messages = {}
     always_send = False
@@ -38,10 +43,29 @@ class AdapterBase:
     def extra_kwargs(self, message_type, **kwargs):
         return {}
 
+    def get_neat_related(self, message_type, related):
+        # We translate the related kwarg into something we can understand
+        try:
+            neat_name = neat_related[message_type]
+        except KeyError:
+            # Message type doesn't expect a related object
+            if related:
+                raise ValueError(f"Unexpected 'related' kwarg provided for {message_type}") from None
+
+        if not related:
+            raise ValueError(f"{message_type} expects a 'related' kwarg")
+        return {neat_name: related}
+
     def recipients(self, message_type, **kwargs):
         raise NotImplementedError()
 
-    def process(self, message_type, event, **kwargs):
+    def process(self, message_type, event, user, submission, related=None):
+        kwargs = {
+            'user': user,
+            'submission': submission,
+            'related': related,
+        }
+        kwargs.update(self.get_neat_related(message_type, related))
         kwargs.update(self.extra_kwargs(message_type, **kwargs))
 
         message = self.message(message_type, **kwargs)
@@ -124,6 +148,7 @@ class ActivityAdapter(AdapterBase):
             submission=submission,
             message=message,
             visibility=visibility,
+            related_object=kwargs['related']
         )
 
 
@@ -265,11 +290,11 @@ class MessengerBackend:
     def __call__(self, message_type, request, user, submission, **kwargs):
         return self.send(message_type, request=request, user=user, submission=submission, **kwargs)
 
-    def send(self, message_type, user, submission, **kwargs):
+    def send(self, message_type, user, submission, related):
         from .models import Event
         event = Event.objects.create(type=message_type.name, by=user, submission=submission)
         for adapter in self.adapters:
-            adapter.process(message_type, event, user=user, submission=submission, **kwargs)
+            adapter.process(message_type, event, user=user, submission=submission, related=related)
 
 
 adapters = [
diff --git a/opentech/apply/activity/migrations/0012_add_generic_relation_to_activity.py b/opentech/apply/activity/migrations/0012_add_generic_relation_to_activity.py
new file mode 100644
index 0000000000000000000000000000000000000000..be9a21f8ab9e406dc485c86033e304fee85cdeb2
--- /dev/null
+++ b/opentech/apply/activity/migrations/0012_add_generic_relation_to_activity.py
@@ -0,0 +1,25 @@
+# Generated by Django 2.0.2 on 2018-09-06 09:43
+
+from django.db import migrations, models
+import django.db.models.deletion
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('contenttypes', '0002_remove_content_type_name'),
+        ('activity', '0011_add_new_event_type'),
+    ]
+
+    operations = [
+        migrations.AddField(
+            model_name='activity',
+            name='content_type',
+            field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='contenttypes.ContentType'),
+        ),
+        migrations.AddField(
+            model_name='activity',
+            name='object_id',
+            field=models.PositiveIntegerField(blank=True, null=True),
+        ),
+    ]
diff --git a/opentech/apply/activity/models.py b/opentech/apply/activity/models.py
index 4aef2ec4c5c1e9bd7921bf798baabb8d9e7cc784..cabc295831be94bc29954fe864d51fe2e33e99ae 100644
--- a/opentech/apply/activity/models.py
+++ b/opentech/apply/activity/models.py
@@ -1,4 +1,6 @@
 from django.conf import settings
+from django.contrib.contenttypes.fields import GenericForeignKey
+from django.contrib.contenttypes.models import ContentType
 from django.db import models
 from django.db.models import Case, When, Value
 from django.db.models.functions import Concat
@@ -81,6 +83,11 @@ class Activity(models.Model):
     message = models.TextField()
     visibility = models.CharField(choices=VISIBILITY.items(), default=PUBLIC, max_length=10)
 
+    # Fields for generic relations to other objects. related_object should implement `get_absolute_url`
+    content_type = models.ForeignKey(ContentType, blank=True, null=True, on_delete=models.CASCADE)
+    object_id = models.PositiveIntegerField(blank=True, null=True)
+    related_object = GenericForeignKey('content_type', 'object_id')
+
     objects = models.Manager.from_queryset(ActivityQuerySet)()
     comments = CommentManger.from_queryset(CommentQueryset)()
     actions = ActionManager.from_queryset(ActionQueryset)()
diff --git a/opentech/apply/determinations/views.py b/opentech/apply/determinations/views.py
index 2225a20aed84cf1d0b2ef5777802bddbd1959d78..8a12b46cc7734fec8530e77e78f274deb489ba94 100644
--- a/opentech/apply/determinations/views.py
+++ b/opentech/apply/determinations/views.py
@@ -92,7 +92,7 @@ class DeterminationCreateOrUpdateView(CreateOrUpdateView):
                 request=self.request,
                 user=self.object.author,
                 submission=self.object.submission,
-                determination=self.object,
+                related=self.object,
             )
             transition = transition_from_outcome(int(form.cleaned_data.get('outcome')), self.submission)