diff --git a/fsl/fslview/displaycontext/group.py b/fsl/fslview/displaycontext/group.py
index 9a41acc1e524b1b714669865b87593647b60916b..493280b96d5a87ccbdd7d09de62de96d6095b795 100644
--- a/fsl/fslview/displaycontext/group.py
+++ b/fsl/fslview/displaycontext/group.py
@@ -10,63 +10,80 @@ import copy
 
 import props
 
-import display as fsldisplay
-import            volumeopts
+import fsl.utils.typedict as td
 
 
 log = logging.getLogger(__name__)
 
 
-
 class OverlayGroup(props.HasProperties):
 
     
-    name     = props.String()
-
-    
     overlays = props.List()
+    """Do not add/remove overlays directly to this list - use the
+    :meth:`addOverlay` and :meth:`removeOverlay` methods.
+    """
 
     
-    # Properties which are linked across all overlays
-    enabled    = copy.copy(fsldisplay.Display.enabled)
-    alpha      = copy.copy(fsldisplay.Display.alpha)
-    brightness = copy.copy(fsldisplay.Display.brightness)
-    contrast   = copy.copy(fsldisplay.Display.contrast)
-
-
-    # Properties which are linked across Image overlays
-    volume = copy.copy(volumeopts.ImageOpts.transform)
-
-    
-    # Properties which are linked across Volume overlays
-    displayRange   = copy.copy(volumeopts.VolumeOpts.displayRange)
-    clippingRange  = copy.copy(volumeopts.VolumeOpts.clippingRange)
-    invertClipping = copy.copy(volumeopts.VolumeOpts.invertClipping)
-    interpolation  = copy.copy(volumeopts.VolumeOpts.interpolation)
+    _groupBindings = td.TypeDict({
+        'Display'        : ['enabled',
+                            'alpha',
+                            'brightness',
+                            'contrast'],
+        'ImageOpts'      : ['volume',
+                            'transform'],
+        'VolumeOpts'     : ['interpolation'],
+        'LabelOpts'      : ['outline',
+                            'outlineWidth'],
+        'ModelOpts'      : ['outline',
+                            'outlineWidth',
+                            'refImage',
+                            'coordSpace',
+                            'transform'],
+        'VectorOpts'     : ['suppressX',
+                            'suppressY',
+                            'suppressZ',
+                            'modulate',
+                            'modThreshold'],
+        'LineVectorOpts' : ['lineWidth',
+                            'directed'],
+        'RGBVectorOpts'  : ['interpolation'],
+    })
+    """This dictionary defines the properties which are bound across Display
+    instances, and instances of the DisplayOpts sub-classes, for overlays in
+    the same group.
+    """
 
     
-    # TODO Vector
-    # TODO Model
-    # TODO Label
-
-    
-    def __init__(self, displayCtx, overlayList, number, name=None):
+    def __init__(self, displayCtx, overlayList):
 
         self.__displayCtx  = displayCtx
         self.__overlayList = overlayList
-        self.__number      = number
+        self.__name        = '{}_{}'.format(type(self).__name__, id(self))
+
+        # Copy all of the properties listed
+        # in the _groupBindings dict
+        from . import       \
+            Display,        \
+            ImageOpts,      \
+            VolumeOpts,     \
+            MaskOpts,       \
+            VectorOpts,     \
+            RGBVectorOpts,  \
+            LineVectorOpts, \
+            ModelOpts,      \
+            LabelOpts
 
-        if name is not None:
-            self.name = name
+        for clsName, propNames in OverlayGroup._groupBindings.items():
+            cls = locals()[clsName]
+
+            for propName in propNames:
+                prop = copy.copy(getattr(cls, propName))
+                self.addProperty('{}_{}'.format(clsName, propName), prop)
 
 
     def __copy__(self):
-        return OverlayGroup(
-            self,
-            self.__displayCtx,
-            self.__overlayList,
-            self.__number,
-            self.name)
+        return OverlayGroup(self, self.__displayCtx, self.__overlayList)
 
             
     def addOverlay(self, overlay):
@@ -76,20 +93,14 @@ class OverlayGroup(props.HasProperties):
         display = self.__displayCtx.getDisplay(overlay)
         opts    = display.getDisplayOpts()
 
-        # This is the first overlay to be added - the group
-        # should inherit its property values
-        if len(self.overlays) == 1: master, slave = display, self
-
-        # Other overlays are already in the group - the
-        # new overlay should inherit the group properties
-        else:                       master, slave = self, display
-
-        slave.bindProps('enabled',    master)
-        slave.bindProps('alpha',      master)
-        slave.bindProps('brightness', master)
-        slave.bindProps('contrast',   master)
+        self.__bindDisplayOpts(display)
+        self.__bindDisplayOpts(opts)
 
+        display.addListener('overlayType',
+                            self.__name,
+                            self.__overlayTypeChanged)
 
+            
     def removeOverlay(self, overlay):
 
         self.overlays.remove(overlay)
@@ -97,11 +108,44 @@ class OverlayGroup(props.HasProperties):
         display = self.__displayCtx.getDisplay(overlay)
         opts    = display.getDisplayOpts()
 
-        self.unbindProps('enabled',    display)
-        self.unbindProps('alpha',      display)
-        self.unbindProps('brightness', display)
-        self.unbindProps('contrast',   display)
+        self.__bindDisplayOpts(display, True)
+        self.__bindDisplayOpts(opts,    True)
+
+        display.removeListener('overlayType', self.__name)
 
 
-    def __overlayTypeChanged(self, *a):
-        pass
+    def __bindDisplayOpts(self, target, unbind=False):
+        
+        # This is the first overlay to be added - the
+        # group should inherit its property values
+        if len(self.overlays) == 1:
+            master, slave = target, self
+                        
+        # Other overlays are already in the group - the
+        # new overlay should inherit the group properties
+        else:
+            master, slave = self, target
+
+        bindProps = OverlayGroup._groupBindings.get(target,
+                                                    allhits=True,
+                                                    bykey=True)
+        
+        for clsName, propNames in bindProps.items():
+            for propName in propNames:
+
+                if slave is self:
+                    otherName = propName
+                    propName  = '{}_{}'.format(clsName, propName)
+                else:
+                    otherName = '{}_{}'.format(clsName, propName)
+
+                slave.bindProps(propName,
+                                master,
+                                otherName,
+                                bindatt=False,
+                                unbind=unbind) 
+
+
+    def __overlayTypeChanged(self, value, valid, display, name):
+        opts = display.getDisplayOpts()
+        self.__bindDisplayOpts(opts)
diff --git a/fsl/tools/fslview.py b/fsl/tools/fslview.py
index a97f9aa6a39332b881b372a37f45714342340321..ddb9e83f658c8e1ef91b276cb9e58253673c0f9c 100644
--- a/fsl/tools/fslview.py
+++ b/fsl/tools/fslview.py
@@ -145,10 +145,7 @@ def context(args):
     # using just one, allowing the user to specify
     # a set of overlays for which their display
     # properties are 'locked'.
-    lockGroup   = displaycontext.OverlayGroup(displayCtx,
-                                              overlayList,
-                                              0,
-                                              'LockGroup')
+    lockGroup   = displaycontext.OverlayGroup(displayCtx, overlayList)
     displayCtx.overlayGroups.append(lockGroup)
 
     log.debug('Created overlay list and master DisplayContext ({})'.format(
diff --git a/fsl/utils/typedict.py b/fsl/utils/typedict.py
index 887eb5447142090ca6627a119de85c9fd3134cea..f66209a2fd7f99637dc102a8440308615dcd2004 100644
--- a/fsl/utils/typedict.py
+++ b/fsl/utils/typedict.py
@@ -51,7 +51,7 @@ class TypeDict(object):
         return key
 
         
-    def get(self, key, default=None, allhits=False):
+    def get(self, key, default=None, allhits=False, bykey=False):
         """Retrieve the value associated with the given key. If
         no value is present, return the specified ``default`` value,
         which itself defaults to ``None``.
@@ -60,13 +60,19 @@ class TypeDict(object):
         ``allhits`` argument evaluates to ``True``, the entire class
         hierarchy is searched, and all values present for the class,
         and any base class, are returned as a sequence.
+
+        If ``allhits`` is ``True`` and the ``bykey`` parameter is also
+        set to ``True``, a dictionary is returned rather than a sequence,
+        where the dictionary contents are the subset of this dictionary,
+        containing the keys which equated to the given key, and their
+        corresponding values.
         """
 
-        try:             return self.__getitem__(key, allhits)
+        try:             return self.__getitem__(key, allhits, bykey)
         except KeyError: return default
 
         
-    def __getitem__(self, key, allhits=False):
+    def __getitem__(self, key, allhits=False, bykey=False):
         
         origKey = key
         key     = self.__tokenifyKey(key)
@@ -95,8 +101,9 @@ class TypeDict(object):
                 newKey.append(elem)
                 bases .append(None)
 
-        key = newKey
+        key  = newKey
 
+        keys = []
         hits = []
             
         while True:
@@ -117,7 +124,9 @@ class TypeDict(object):
 
                 # Otherwise, accumulate the value, and keep
                 # searching
-                else:           hits.append(val)
+                else:
+                    keys.append(lKey)
+                    hits.append(val)
 
             # No more base classes to search for - there
             # really is no value associated with this key
@@ -135,16 +144,30 @@ class TypeDict(object):
                 for elemBase in elemBases:
 
                     newKey    = list(key)
-                    newKey[i] = elemBase
+                    newKey[i] = elemBase.__name__
+
+                    if len(newKey) == 1: newKey = newKey[0]
+                    else:                newKey = tuple(newKey)
 
-                    try:             val = self.__getitem__(tuple(newKey))
+                    try:             val = self.__getitem__(newKey)
                     except KeyError: continue
 
                     if not allhits: return val
-                    else:           hits.append(val)
+                    else:
+                        keys.append(newKey)
+                        hits.append(val)
 
             # No value for any base classes either
             if len(hits) == 0:
                 raise KeyError(origKey)
+
+            # if bykey is true, return a dict
+            # containing the values and their
+            # corresponding keys
+            if bykey:
+                return dict(zip(keys, hits))
+
+            # otherwise just return the
+            # list of matched values
             else:
                 return hits