diff --git include/clang/Basic/DiagnosticSemaKinds.td include/clang/Basic/DiagnosticSemaKinds.td
index c300d6f..1ef40e4 100644
--- include/clang/Basic/DiagnosticSemaKinds.td
+++ include/clang/Basic/DiagnosticSemaKinds.td
@@ -5368,7 +5368,7 @@ def err_objc_object_catch : Error<
 def err_incomplete_type_objc_at_encode : Error<
   "'@encode' of incomplete type %0">;
 def warn_objc_circular_container : Warning<
-  "adding '%0' to '%0' might cause circular dependency in container">,
+  "adding '%0' to '%1' might cause circular dependency in container">,
   InGroup<DiagGroup<"objc-circular-container">>;
 def note_objc_circular_container_declared_here : Note<"'%0' declared here">;
 
diff --git lib/Sema/SemaChecking.cpp lib/Sema/SemaChecking.cpp
index d9d26e2..27d3b55 100644
--- lib/Sema/SemaChecking.cpp
+++ lib/Sema/SemaChecking.cpp
@@ -8743,7 +8743,25 @@ static Optional<int> GetNSMutableArrayArgumentIndex(Sema &S,
       S.Context.getObjCObjectPointerType(NSMutableArrayObject);
   }
 
-  if (S.NSMutableArrayPointer != Message->getReceiverType()) {
+  ObjCInterfaceDecl *Receiver = Message->getReceiverInterface();
+  if (!Receiver) {
+    return None;
+  }
+
+  bool IsMutableArray = false;
+  do {
+    QualType QT = S.Context.getObjCInterfaceType(Receiver);
+    QualType ReceiverType = S.Context.getObjCObjectPointerType(QT);
+
+    IsMutableArray = !S.NSMutableArrayPointer.isNull() &&
+      ReceiverType == S.NSMutableArrayPointer;
+
+    if (IsMutableArray) {
+      break;
+    }
+  } while ((Receiver = Receiver->getSuperClass()));
+
+  if (!IsMutableArray) {
     return None;
   }
 
@@ -8792,7 +8810,25 @@ Optional<int> GetNSMutableDictionaryArgumentIndex(Sema &S,
       S.Context.getObjCObjectPointerType(NSMutableDictionaryObject);
   }
 
-  if (S.NSMutableDictionaryPointer != Message->getReceiverType()) {
+  ObjCInterfaceDecl *Receiver = Message->getReceiverInterface();
+  if (!Receiver) {
+    return None;
+  }
+
+  bool IsMutableDictionary = false;
+  do {
+    QualType QT = S.Context.getObjCInterfaceType(Receiver);
+    QualType ReceiverType = S.Context.getObjCObjectPointerType(QT);
+
+    IsMutableDictionary = !S.NSMutableDictionaryPointer.isNull() &&
+      ReceiverType == S.NSMutableDictionaryPointer;
+
+    if (IsMutableDictionary) {
+      break;
+    }
+  } while ((Receiver = Receiver->getSuperClass()));
+
+  if (!IsMutableDictionary) {
     return None;
   }
 
@@ -8867,14 +8903,29 @@ static Optional<int> GetNSSetArgumentIndex(Sema &S, ObjCMessageExpr *Message) {
     }
   }
 
-  QualType ReceiverType = Message->getReceiverType();
+  ObjCInterfaceDecl *Receiver = Message->getReceiverInterface();
+  if (!Receiver) {
+    return None;
+  }
+
+  bool IsMutableSet = false;
+  bool IsMutableOrderedSet = false;
+  bool IsCountedSet = false;
+  do {
+    QualType QT = S.Context.getObjCInterfaceType(Receiver);
+    QualType ReceiverType = S.Context.getObjCObjectPointerType(QT);
+
+    IsMutableSet = !S.NSMutableSetPointer.isNull() &&
+      ReceiverType == S.NSMutableSetPointer;
+    IsMutableOrderedSet = !S.NSMutableOrderedSetPointer.isNull() &&
+      ReceiverType == S.NSMutableOrderedSetPointer;
+    IsCountedSet = !S.NSCountedSetPointer.isNull() &&
+      ReceiverType == S.NSCountedSetPointer;
 
-  bool IsMutableSet = !S.NSMutableSetPointer.isNull() &&
-    ReceiverType == S.NSMutableSetPointer;
-  bool IsMutableOrderedSet = !S.NSMutableOrderedSetPointer.isNull() &&
-    ReceiverType == S.NSMutableOrderedSetPointer;
-  bool IsCountedSet = !S.NSCountedSetPointer.isNull() &&
-    ReceiverType == S.NSCountedSetPointer;
+    if (IsMutableSet || IsMutableOrderedSet || IsCountedSet) {
+      break;
+    }
+  } while ((Receiver = Receiver->getSuperClass()));
 
   if (!IsMutableSet && !IsMutableOrderedSet && !IsCountedSet) {
     return None;
@@ -8917,38 +8968,51 @@ void Sema::CheckObjCCircularContainer(ObjCMessageExpr *Message) {
 
   int ArgIndex = *ArgOpt;
 
-  Expr *Receiver = Message->getInstanceReceiver()->IgnoreImpCasts();
-  if (OpaqueValueExpr *OE = dyn_cast<OpaqueValueExpr>(Receiver)) {
-    Receiver = OE->getSourceExpr()->IgnoreImpCasts();
-  }
-
   Expr *Arg = Message->getArg(ArgIndex)->IgnoreImpCasts();
   if (OpaqueValueExpr *OE = dyn_cast<OpaqueValueExpr>(Arg)) {
     Arg = OE->getSourceExpr()->IgnoreImpCasts();
   }
 
-  if (DeclRefExpr *ReceiverRE = dyn_cast<DeclRefExpr>(Receiver)) {
+  if (Message->getReceiverKind() == ObjCMessageExpr::SuperInstance) {
     if (DeclRefExpr *ArgRE = dyn_cast<DeclRefExpr>(Arg)) {
-      if (ReceiverRE->getDecl() == ArgRE->getDecl()) {
-        ValueDecl *Decl = ReceiverRE->getDecl();
+      if (ArgRE->isObjCSelfExpr()) {
         Diag(Message->getSourceRange().getBegin(),
              diag::warn_objc_circular_container)
-          << Decl->getName();
-        Diag(Decl->getLocation(),
-             diag::note_objc_circular_container_declared_here)
-          << Decl->getName();
+          << ArgRE->getDecl()->getName() << StringRef("super");
       }
     }
-  } else if (ObjCIvarRefExpr *IvarRE = dyn_cast<ObjCIvarRefExpr>(Receiver)) {
-    if (ObjCIvarRefExpr *IvarArgRE = dyn_cast<ObjCIvarRefExpr>(Arg)) {
-      if (IvarRE->getDecl() == IvarArgRE->getDecl()) {
-        ObjCIvarDecl *Decl = IvarRE->getDecl();
-        Diag(Message->getSourceRange().getBegin(),
-             diag::warn_objc_circular_container)
-          << Decl->getName();
-        Diag(Decl->getLocation(),
-             diag::note_objc_circular_container_declared_here)
-          << Decl->getName();
+  } else {
+    Expr *Receiver = Message->getInstanceReceiver()->IgnoreImpCasts();
+
+    if (OpaqueValueExpr *OE = dyn_cast<OpaqueValueExpr>(Receiver)) {
+      Receiver = OE->getSourceExpr()->IgnoreImpCasts();
+    }
+
+    if (DeclRefExpr *ReceiverRE = dyn_cast<DeclRefExpr>(Receiver)) {
+      if (DeclRefExpr *ArgRE = dyn_cast<DeclRefExpr>(Arg)) {
+        if (ReceiverRE->getDecl() == ArgRE->getDecl()) {
+          ValueDecl *Decl = ReceiverRE->getDecl();
+          Diag(Message->getSourceRange().getBegin(),
+               diag::warn_objc_circular_container)
+            << Decl->getName() << Decl->getName();
+          if (!ArgRE->isObjCSelfExpr()) {
+            Diag(Decl->getLocation(),
+                 diag::note_objc_circular_container_declared_here)
+              << Decl->getName();
+          }
+        }
+      }
+    } else if (ObjCIvarRefExpr *IvarRE = dyn_cast<ObjCIvarRefExpr>(Receiver)) {
+      if (ObjCIvarRefExpr *IvarArgRE = dyn_cast<ObjCIvarRefExpr>(Arg)) {
+        if (IvarRE->getDecl() == IvarArgRE->getDecl()) {
+          ObjCIvarDecl *Decl = IvarRE->getDecl();
+          Diag(Message->getSourceRange().getBegin(),
+               diag::warn_objc_circular_container)
+            << Decl->getName() << Decl->getName();
+          Diag(Decl->getLocation(),
+               diag::note_objc_circular_container_declared_here)
+            << Decl->getName();
+        }
       }
     }
   }
diff --git test/SemaObjC/circular-container.m test/SemaObjC/circular-container.m
index 1a2a24e..1f06595 100644
--- test/SemaObjC/circular-container.m
+++ test/SemaObjC/circular-container.m
@@ -144,3 +144,64 @@ void checkNSMutableOrderedSet() {
   [s replaceObjectAtIndex:0 withObject:s]; // expected-warning {{adding 's' to 's' might cause circular dependency in container}}
 }
 
+// Test subclassing
+
+@interface FootableSet : NSMutableSet
+@end
+
+@implementation FootableSet
+- (void)meth {
+  [super addObject:self]; // expected-warning {{adding 'self' to 'super' might cause circular dependency in container}}
+  [super addObject:nil]; // no-warning
+  [self addObject:self]; // expected-warning {{adding 'self' to 'self' might cause circular dependency in container}}
+}
+@end
+
+@interface FootableArray : NSMutableArray
+@end
+
+@implementation FootableArray
+- (void)meth {
+  [super addObject:self]; // expected-warning {{adding 'self' to 'super' might cause circular dependency in container}}
+  [super addObject:nil]; // no-warning
+  [self addObject:self]; // expected-warning {{adding 'self' to 'self' might cause circular dependency in container}}
+}
+@end
+
+@interface FootableDictionary : NSMutableDictionary
+@end
+
+@implementation FootableDictionary
+- (void)meth {
+  [super setObject:self forKey:@"key"]; // expected-warning {{adding 'self' to 'super' might cause circular dependency in container}}
+  [super setObject:nil forKey:@"key"]; // no-warning
+  [self setObject:self forKey:@"key"]; // expected-warning {{adding 'self' to 'self' might cause circular dependency in container}}
+}
+@end
+
+
+void subclassingNSMutableArray() {
+  FootableArray *a = nil; // expected-note 5 {{'a' declared here}} 5
+
+  [a addObject:a]; // expected-warning {{adding 'a' to 'a' might cause circular dependency in container}}
+  [a insertObject:a atIndex:0]; // expected-warning {{adding 'a' to 'a' might cause circular dependency in container}}
+  [a replaceObjectAtIndex:0 withObject:a]; // expected-warning {{adding 'a' to 'a' might cause circular dependency in container}}
+  [a setObject:a atIndexedSubscript:0]; // expected-warning {{adding 'a' to 'a' might cause circular dependency in container}}
+  a[0] = a; // expected-warning {{adding 'a' to 'a' might cause circular dependency in container}}
+}
+
+void subclassingNSMutableDictionary() {
+  FootableDictionary *d = nil; // expected-note 4 {{'d' declared here}}
+
+  [d setObject:d forKey:@"key"]; // expected-warning {{adding 'd' to 'd' might cause circular dependency in container}}
+  [d setObject:d forKeyedSubscript:@"key"]; // expected-warning {{adding 'd' to 'd' might cause circular dependency in container}}
+  [d setValue:d forKey:@"key"]; // expected-warning {{adding 'd' to 'd' might cause circular dependency in container}}
+  d[@"key"] = d; // expected-warning {{adding 'd' to 'd' might cause circular dependency in container}}
+}
+
+void subclassingNSMutableSet() {
+  FootableSet *s = nil; // expected-note {{'s' declared here}}
+
+  [s addObject:s]; // expected-warning {{adding 's' to 's' might cause circular dependency in container}}
+}
+
