diff --git a/gracedb/events/models.py b/gracedb/events/models.py
index c72a3fe077a837372d8b39ca14401979afb9732a..cca02a8b8326bf85a85a1c935d199afd7adb829f 100644
--- a/gracedb/events/models.py
+++ b/gracedb/events/models.py
@@ -193,6 +193,24 @@ class Event(models.Model):
         nodes.append(hdf.read())
         return os.path.join(settings.GRACEDB_DATA_DIR, *nodes)
 
+    def is_test(self):
+        return self.group.name == 'Test'
+
+    def is_mdc(self):
+        return (self.search and self.search.name == 'MDC' and
+                self.group.name != 'Test')
+
+    def is_production(self):
+        return not (self.is_test() or self.is_mdc())
+
+    def get_event_category(self):
+        if self.is_test():
+            return 'Test'
+        elif self.is_mdc():
+            return 'MDC'
+        else:
+            return 'Production'
+
     def ligoApproved(self):
         return self.approval_set.filter(approvingCollaboration='L').count()
 
diff --git a/gracedb/superevents/models.py b/gracedb/superevents/models.py
index 27b25a3cdc546ebc83b2b98657abb91e6d545bbd..80d2509ef03c0e62c13e6338d87af823150a2252 100644
--- a/gracedb/superevents/models.py
+++ b/gracedb/superevents/models.py
@@ -208,6 +208,40 @@ class Superevent(CleanSaveModel, ModelToDictMixin, AutoIncrementModel):
         # Call base class delete
         super(Superevent, self).delete(*args, **kwargs)
 
+    def event_compatible(self, event):
+        """
+        Check whether an event is of the correct type to be part of this
+        superevent
+        """
+        return self.__class__.event_category_check(event, self.category)
+
+    @classmethod
+    def event_category_check(cls, event, superevent_category):
+        """
+        Given a superevent type, check whether an event could be added to such
+        a superevent
+        """
+        if (superevent_category == cls.SUPEREVENT_CATEGORY_TEST and
+            not event.is_test()):
+            return False
+        elif (superevent_category == cls.SUPEREVENT_CATEGORY_MDC and
+              not event.is_mdc()):
+            return False
+        elif (superevent_category == cls.SUPEREVENT_CATEGORY_PRODUCTION and
+              (event.is_test() or event.is_mdc())):
+            return False
+        else:
+            return True
+
+    def is_production(self):
+        return self.category == self.SUPEREVENT_CATEGORY_PRODUCTION
+
+    def is_test(self):
+        return self.category == self.SUPEREVENT_CATEGORY_TEST
+
+    def is_mdc(self):
+        return self.category == self.SUPEREVENT_CATEGORY_MDC
+
     def confirm_as_gw(self):
         """
         Sets is_gw to True, calculates the gw_date_number in the database, and
@@ -415,6 +449,11 @@ class Superevent(CleanSaveModel, ModelToDictMixin, AutoIncrementModel):
         # one that datetime can't parse or that the regex won't match
         pass
 
+    class EventTypeMismatchError(Exception):
+        # To be raised when an attempt is made to add an event with an
+        # incompatible type
+        pass
+
 
 class Log(CleanSaveModel, LogBase, AutoIncrementModel):
     """