diff --git a/lib/Serialization/ASTReaderDecl.cpp b/lib/Serialization/ASTReaderDecl.cpp
index 05d3bab9a7dc448069af5774abaeb36348c9df3a..3e24145075eec4d682672c43fe73e6aa87c07f36 100644
--- a/lib/Serialization/ASTReaderDecl.cpp
+++ b/lib/Serialization/ASTReaderDecl.cpp
@@ -2019,6 +2019,8 @@ void ASTDeclReader::mergeRedeclarable(Redeclarable<T> *DBase,
   T *D = static_cast<T*>(DBase);
   T *DCanon = D->getCanonicalDecl();
   if (D != DCanon &&
+      // IDs < NUM_PREDEF_DECL_IDS are not loaded from an AST file.
+      Redecl.getFirstID() >= NUM_PREDEF_DECL_IDS &&
       (!Reader.getContext().getLangOpts().Modules ||
        Reader.getOwningModuleFile(DCanon) == Reader.getOwningModuleFile(D))) {
     // All redeclarations between this declaration and its originally-canonical
diff --git a/test/Index/Inputs/declare-objc-predef.h b/test/Index/Inputs/declare-objc-predef.h
new file mode 100644
index 0000000000000000000000000000000000000000..6a03c4f88d218789453ed3a4b4af3d9356f69e69
--- /dev/null
+++ b/test/Index/Inputs/declare-objc-predef.h
@@ -0,0 +1,3 @@
+@class Protocol;
+typedef struct objc_class *Class
+@class id;
diff --git a/test/Index/reparse-predef-objc-protocol.m b/test/Index/reparse-predef-objc-protocol.m
new file mode 100644
index 0000000000000000000000000000000000000000..fc9d8572e0c185d5e361e13203474c0d754468f3
--- /dev/null
+++ b/test/Index/reparse-predef-objc-protocol.m
@@ -0,0 +1,9 @@
+// RUN: env CINDEXTEST_EDITING=1 c-index-test -test-load-source-reparse 3 local %s -I %S/Inputs
+#import "declare-objc-predef.h"
+// PR20633
+
+// CHECK: declare-objc-predef.h:1:8: ObjCInterfaceDecl=Protocol:1:8 Extent=[1:1 - 1:16]
+// CHECK: declare-objc-predef.h:1:8: ObjCClassRef=Protocol:1:8 Extent=[1:8 - 1:16]
+// CHECK: declare-objc-predef.h:2:16: StructDecl=objc_class:2:16 Extent=[2:9 - 2:26]
+// CHECK: declare-objc-predef.h:2:28: TypedefDecl=Class:2:28 (Definition) Extent=[2:1 - 2:33]
+// CHECK: declare-objc-predef.h:2:16: TypeRef=struct objc_class:2:16 Extent=[2:16 - 2:26]