Add ObjC helpers for Any WKT.

- Capture the ObjC prefix used when generating the the file.
- Track the containing type on descriptors.
- Mark descriptors where the message class name got a suffix added to it.
- Expose a fullName property on Descriptors.
- Add helpers for packing/unpacking Any messages.
- Bump the ObjC runtime version number. Since we added methods and invoke them
  in the generated code, ensure the code is running against a matching version.
  Otherwise, someone could compile against headers, but run with a framework
  that is older and get unknown selector failures.  This should trip clearer
  messaging.

Fixes https://github.com/google/protobuf/issues/1674
diff --git a/objectivec/DevTools/compile_testing_protos.sh b/objectivec/DevTools/compile_testing_protos.sh
index 35a8504..6cc32da 100755
--- a/objectivec/DevTools/compile_testing_protos.sh
+++ b/objectivec/DevTools/compile_testing_protos.sh
@@ -93,6 +93,7 @@
 # sources can be generated from them.
 
 CORE_PROTO_FILES=(
+  src/google/protobuf/any_test.proto
   src/google/protobuf/unittest_arena.proto
   src/google/protobuf/unittest_custom_options.proto
   src/google/protobuf/unittest_enormous_descriptor.proto
diff --git a/objectivec/GPBBootstrap.h b/objectivec/GPBBootstrap.h
index 2e5bdc7..7dc943d 100644
--- a/objectivec/GPBBootstrap.h
+++ b/objectivec/GPBBootstrap.h
@@ -99,4 +99,4 @@
 // regenerated.
 //
 // Meant to be used internally by generated code.
-#define GOOGLE_PROTOBUF_OBJC_GEN_VERSION 30001
+#define GOOGLE_PROTOBUF_OBJC_GEN_VERSION 30002
diff --git a/objectivec/GPBDescriptor.h b/objectivec/GPBDescriptor.h
index 36fb4ea..651f4de 100644
--- a/objectivec/GPBDescriptor.h
+++ b/objectivec/GPBDescriptor.h
@@ -81,6 +81,13 @@
 @property(nonatomic, readonly, getter=isWireFormat) BOOL wireFormat;
 /** The class of this message. */
 @property(nonatomic, readonly) Class messageClass;
+/** Containing message descriptor if this message is nested, or nil otherwise. */
+@property(readonly, nullable) GPBDescriptor *containingType;
+/**
+ * Fully qualified name for this message (package.message). Can be nil if the
+ * value is unable to be computed.
+ */
+@property(readonly, nullable) NSString *fullName;
 
 /**
  * Gets the field for the given number.
@@ -118,6 +125,8 @@
 
 /** The package declared in the proto file. */
 @property(nonatomic, readonly, copy) NSString *package;
+/** The objc prefix declared in the proto file. */
+@property(nonatomic, readonly, copy, nullable) NSString *objcPrefix;
 /** The syntax of the proto file. */
 @property(nonatomic, readonly) GPBFileSyntax syntax;
 
diff --git a/objectivec/GPBDescriptor.m b/objectivec/GPBDescriptor.m
index dccb9bc..0753a94 100644
--- a/objectivec/GPBDescriptor.m
+++ b/objectivec/GPBDescriptor.m
@@ -42,8 +42,10 @@
 #pragma clang diagnostic push
 #pragma clang diagnostic ignored "-Wdirect-ivar-access"
 
-// The address of this variable is used as a key for obj_getAssociatedObject.
+// The addresses of these variables are used as keys for objc_getAssociatedObject.
 static const char kTextFormatExtraValueKey = 0;
+static const char kParentClassNameValueKey = 0;
+static const char kClassNameSuffixKey = 0;
 
 // Utility function to generate selectors on the fly.
 static SEL SelFromStrings(const char *prefix, const char *middle,
@@ -215,10 +217,102 @@
   extensionRangesCount_ = count;
 }
 
+- (void)setupContainingMessageClassName:(const char *)msgClassName {
+  // Note: Only fetch the class here, can't send messages to it because
+  // that could cause cycles back to this class within +initialize if
+  // two messages have each other in fields (i.e. - they build a graph).
+  NSAssert(objc_getClass(msgClassName), @"Class %s not defined", msgClassName);
+  NSValue *parentNameValue = [NSValue valueWithPointer:msgClassName];
+  objc_setAssociatedObject(self, &kParentClassNameValueKey,
+                           parentNameValue,
+                           OBJC_ASSOCIATION_RETAIN_NONATOMIC);
+}
+
+- (void)setupMessageClassNameSuffix:(NSString *)suffix {
+  if (suffix.length) {
+    objc_setAssociatedObject(self, &kClassNameSuffixKey,
+                             suffix,
+                             OBJC_ASSOCIATION_RETAIN_NONATOMIC);
+  }
+}
+
 - (NSString *)name {
   return NSStringFromClass(messageClass_);
 }
 
+- (GPBDescriptor *)containingType {
+  NSValue *parentNameValue =
+      objc_getAssociatedObject(self, &kParentClassNameValueKey);
+  if (!parentNameValue) {
+    return nil;
+  }
+  const char *parentName = [parentNameValue pointerValue];
+  Class parentClass = objc_getClass(parentName);
+  NSAssert(parentClass, @"Class %s not defined", parentName);
+  return [parentClass descriptor];
+}
+
+- (NSString *)fullName {
+  NSString *className = NSStringFromClass(self.messageClass);
+  GPBFileDescriptor *file = self.file;
+  NSString *objcPrefix = file.objcPrefix;
+  if (objcPrefix && ![className hasPrefix:objcPrefix]) {
+    NSAssert(0,
+             @"Class didn't have correct prefix? (%@ - %@)",
+             className, objcPrefix);
+    return nil;
+  }
+  GPBDescriptor *parent = self.containingType;
+
+  NSString *name = nil;
+  if (parent) {
+    NSString *parentClassName = NSStringFromClass(parent.messageClass);
+    // The generator will add _Class to avoid reserved words, drop it.
+    NSString *suffix = objc_getAssociatedObject(parent, &kClassNameSuffixKey);
+    if (suffix) {
+      if (![parentClassName hasSuffix:suffix]) {
+        NSAssert(0,
+                 @"ParentMessage class didn't have correct suffix? (%@ - %@)",
+                 className, suffix);
+        return nil;
+      }
+      parentClassName =
+          [parentClassName substringToIndex:(parentClassName.length - suffix.length)];
+    }
+    NSString *parentPrefix = [parentClassName stringByAppendingString:@"_"];
+    if (![className hasPrefix:parentPrefix]) {
+      NSAssert(0,
+               @"Class didn't have the correct parent name prefix? (%@ - %@)",
+               parentPrefix, className);
+      return nil;
+    }
+    name = [className substringFromIndex:parentPrefix.length];
+  } else {
+    name = [className substringFromIndex:objcPrefix.length];
+  }
+
+  // The generator will add _Class to avoid reserved words, drop it.
+  NSString *suffix = objc_getAssociatedObject(self, &kClassNameSuffixKey);
+  if (suffix) {
+    if (![name hasSuffix:suffix]) {
+      NSAssert(0,
+               @"Message class didn't have correct suffix? (%@ - %@)",
+               name, suffix);
+      return nil;
+    }
+    name = [name substringToIndex:(name.length - suffix.length)];
+  }
+
+  NSString *prefix = (parent != nil ? parent.fullName : file.package);
+  NSString *result;
+  if (prefix.length > 0) {
+    result = [NSString stringWithFormat:@"%@.%@", prefix, name];
+  } else {
+    result = name;
+  }
+  return result;
+}
+
 - (id)copyWithZone:(NSZone *)zone {
 #pragma unused(zone)
   return [self retain];
@@ -255,13 +349,27 @@
 
 @implementation GPBFileDescriptor {
   NSString *package_;
+  NSString *objcPrefix_;
   GPBFileSyntax syntax_;
 }
 
 @synthesize package = package_;
+@synthesize objcPrefix = objcPrefix_;
 @synthesize syntax = syntax_;
 
 - (instancetype)initWithPackage:(NSString *)package
+                     objcPrefix:(NSString *)objcPrefix
+                         syntax:(GPBFileSyntax)syntax {
+  self = [super init];
+  if (self) {
+    package_ = [package copy];
+    objcPrefix_ = [objcPrefix copy];
+    syntax_ = syntax;
+  }
+  return self;
+}
+
+- (instancetype)initWithPackage:(NSString *)package
                          syntax:(GPBFileSyntax)syntax {
   self = [super init];
   if (self) {
@@ -273,6 +381,7 @@
 
 - (void)dealloc {
   [package_ release];
+  [objcPrefix_ release];
   [super dealloc];
 }
 
@@ -416,6 +525,9 @@
     // Extra type specific data.
     if (isMessage) {
       const char *className = coreDesc->dataTypeSpecific.className;
+      // Note: Only fetch the class here, can't send messages to it because
+      // that could cause cycles back to this class within +initialize if
+      // two messages have each other in fields (i.e. - they build a graph).
       msgClass_ = objc_getClass(className);
       NSAssert(msgClass_, @"Class %s not defined", className);
     } else if (dataType == GPBDataTypeEnum) {
diff --git a/objectivec/GPBDescriptor_PackagePrivate.h b/objectivec/GPBDescriptor_PackagePrivate.h
index c20ff6b..66a4db7 100644
--- a/objectivec/GPBDescriptor_PackagePrivate.h
+++ b/objectivec/GPBDescriptor_PackagePrivate.h
@@ -165,11 +165,16 @@
       firstHasIndex:(int32_t)firstHasIndex;
 - (void)setupExtraTextInfo:(const char *)extraTextFormatInfo;
 - (void)setupExtensionRanges:(const GPBExtensionRange *)ranges count:(int32_t)count;
+- (void)setupContainingMessageClassName:(const char *)msgClassName;
+- (void)setupMessageClassNameSuffix:(NSString *)suffix;
 
 @end
 
 @interface GPBFileDescriptor ()
 - (instancetype)initWithPackage:(NSString *)package
+                     objcPrefix:(NSString *)objcPrefix
+                         syntax:(GPBFileSyntax)syntax;
+- (instancetype)initWithPackage:(NSString *)package
                          syntax:(GPBFileSyntax)syntax;
 @end
 
diff --git a/objectivec/GPBWellKnownTypes.h b/objectivec/GPBWellKnownTypes.h
index 96d51d9..9ea5729 100644
--- a/objectivec/GPBWellKnownTypes.h
+++ b/objectivec/GPBWellKnownTypes.h
@@ -37,15 +37,32 @@
 #endif
 
 #if GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS
+ #import <Protobuf/Any.pbobjc.h>
  #import <Protobuf/Duration.pbobjc.h>
  #import <Protobuf/Timestamp.pbobjc.h>
 #else
+ #import "google/protobuf/Any.pbobjc.h"
  #import "google/protobuf/Duration.pbobjc.h"
  #import "google/protobuf/Timestamp.pbobjc.h"
 #endif
 
 NS_ASSUME_NONNULL_BEGIN
 
+#pragma mark - Errors
+
+/** NSError domain used for errors. */
+extern NSString *const GPBWellKnownTypesErrorDomain;
+
+/** Error code for NSError with GPBWellKnownTypesErrorDomain. */
+typedef NS_ENUM(NSInteger, GPBWellKnownTypesErrorCode) {
+  /** The type_url could not be computed for the requested GPBMessage class. */
+  GPBWellKnownTypesErrorCodeFailedToComputeTypeURL = -100,
+  /** type_url in a Any doesn’t match that of the requested GPBMessage class. */
+  GPBWellKnownTypesErrorCodeTypeURLMismatch = -101,
+};
+
+#pragma mark - GPBTimestamp
+
 /**
  * Category for GPBTimestamp to work with standard Foundation time/date types.
  **/
@@ -77,6 +94,8 @@
 
 @end
 
+#pragma mark - GPBDuration
+
 /**
  * Category for GPBDuration to work with standard Foundation time type.
  **/
@@ -96,4 +115,110 @@
 
 @end
 
+#pragma mark - GPBAny
+
+/**
+ * Category for GPBAny to help work with the message within the object.
+ **/
+@interface GPBAny (GBPWellKnownTypes)
+
+/**
+ * Convenience method to create a GPBAny containing the serialized message.
+ * This uses type.googleapis.com/ as the type_url's prefix.
+ *
+ * @param message  The message to be packed into the GPBAny.
+ * @param errorPtr Pointer to an error that will be populated if something goes
+ *                 wrong.
+ *
+ * @return A newly configured GPBAny with the given message, or nil on failure.
+ */
++ (nullable instancetype)anyWithMessage:(nonnull GPBMessage *)message
+                                  error:(NSError **)errorPtr;
+
+/**
+ * Convenience method to create a GPBAny containing the serialized message.
+ *
+ * @param message       The message to be packed into the GPBAny.
+ * @param typeURLPrefix The URL prefix to apply for type_url.
+ * @param errorPtr      Pointer to an error that will be populated if something
+ *                      goes wrong.
+ *
+ * @return A newly configured GPBAny with the given message, or nil on failure.
+ */
++ (nullable instancetype)anyWithMessage:(nonnull GPBMessage *)message
+                          typeURLPrefix:(nonnull NSString *)typeURLPrefix
+                                  error:(NSError **)errorPtr;
+
+/**
+ * Initializes a GPBAny to contain the serialized message. This uses
+ * type.googleapis.com/ as the type_url's prefix.
+ *
+ * @param message  The message to be packed into the GPBAny.
+ * @param errorPtr Pointer to an error that will be populated if something goes
+ *                 wrong.
+ *
+ * @return A newly configured GPBAny with the given message, or nil on failure.
+ */
+- (nullable instancetype)initWithMessage:(nonnull GPBMessage *)message
+                                   error:(NSError **)errorPtr;
+
+/**
+ * Initializes a GPBAny to contain the serialized message.
+ *
+ * @param message       The message to be packed into the GPBAny.
+ * @param typeURLPrefix The URL prefix to apply for type_url.
+ * @param errorPtr      Pointer to an error that will be populated if something
+ *                      goes wrong.
+ *
+ * @return A newly configured GPBAny with the given message, or nil on failure.
+ */
+- (nullable instancetype)initWithMessage:(nonnull GPBMessage *)message
+                           typeURLPrefix:(nonnull NSString *)typeURLPrefix
+                                   error:(NSError **)errorPtr;
+
+/**
+ * Packs the serialized message into this GPBAny. This uses
+ * type.googleapis.com/ as the type_url's prefix.
+ *
+ * @param message  The message to be packed into the GPBAny.
+ * @param errorPtr Pointer to an error that will be populated if something goes
+ *                 wrong.
+ *
+ * @return Whether the packing was successful or not.
+ */
+- (BOOL)packWithMessage:(nonnull GPBMessage *)message
+                  error:(NSError **)errorPtr;
+
+/**
+ * Packs the serialized message into this GPBAny.
+ *
+ * @param message       The message to be packed into the GPBAny.
+ * @param typeURLPrefix The URL prefix to apply for type_url.
+ * @param errorPtr      Pointer to an error that will be populated if something
+ *                      goes wrong.
+ *
+ * @return Whether the packing was successful or not.
+ */
+- (BOOL)packWithMessage:(nonnull GPBMessage *)message
+          typeURLPrefix:(nonnull NSString *)typeURLPrefix
+                  error:(NSError **)errorPtr;
+
+/**
+ * Unpacks the serialized message as if it was an instance of the given class.
+ *
+ * @note When checking type_url, the base URL is not checked, only the fully
+ *       qualified name.
+ *
+ * @param messageClass The class to use to deserialize the contained message.
+ * @param errorPtr     Pointer to an error that will be populated if something
+ *                     goes wrong.
+ *
+ * @return An instance of the given class populated with the contained data, or
+ *         nil on failure.
+ */
+- (nullable GPBMessage *)unpackMessageClass:(Class)messageClass
+                                      error:(NSError **)errorPtr;
+
+@end
+
 NS_ASSUME_NONNULL_END
diff --git a/objectivec/GPBWellKnownTypes.m b/objectivec/GPBWellKnownTypes.m
index 5cdd62d..ed798a2 100644
--- a/objectivec/GPBWellKnownTypes.m
+++ b/objectivec/GPBWellKnownTypes.m
@@ -34,6 +34,13 @@
 
 #import "GPBWellKnownTypes.h"
 
+#import "GPBUtilities_PackagePrivate.h"
+
+NSString *const GPBWellKnownTypesErrorDomain =
+    GPBNSStringifySymbol(GPBWellKnownTypesErrorDomain);
+
+static NSString *kTypePrefixGoogleApisCom = @"type.googleapis.com/";
+
 static NSTimeInterval TimeIntervalSince1970FromSecondsAndNanos(int64_t seconds,
                                                                int32_t nanos) {
   return seconds + (NSTimeInterval)nanos / 1e9;
@@ -48,6 +55,30 @@
   return (int32_t)nanos;
 }
 
+static NSString *BuildTypeURL(NSString *typeURLPrefix, NSString *fullName) {
+  if (typeURLPrefix.length == 0) {
+    return fullName;
+  }
+
+  if ([typeURLPrefix hasSuffix:@"/"]) {
+    return [typeURLPrefix stringByAppendingString:fullName];
+  }
+
+  return [NSString stringWithFormat:@"%@/%@", typeURLPrefix, fullName];
+}
+
+static NSString *ParseTypeFromURL(NSString *typeURLString) {
+  NSRange range = [typeURLString rangeOfString:@"/" options:NSBackwardsSearch];
+  if ((range.location == NSNotFound) ||
+      (NSMaxRange(range) == typeURLString.length)) {
+    return nil;
+  }
+  NSString *result = [typeURLString substringFromIndex:range.location + 1];
+  return result;
+}
+
+#pragma mark - GPBTimestamp
+
 @implementation GPBTimestamp (GBPWellKnownTypes)
 
 - (instancetype)initWithDate:(NSDate *)date {
@@ -87,6 +118,8 @@
 
 @end
 
+#pragma mark - GPBDuration
+
 @implementation GPBDuration (GBPWellKnownTypes)
 
 - (instancetype)initWithTimeIntervalSince1970:(NSTimeInterval)timeIntervalSince1970 {
@@ -113,3 +146,105 @@
 }
 
 @end
+
+#pragma mark - GPBAny
+
+@implementation GPBAny (GBPWellKnownTypes)
+
++ (instancetype)anyWithMessage:(GPBMessage *)message
+                         error:(NSError **)errorPtr {
+  return [self anyWithMessage:message
+                typeURLPrefix:kTypePrefixGoogleApisCom
+                        error:errorPtr];
+}
+
++ (instancetype)anyWithMessage:(GPBMessage *)message
+                 typeURLPrefix:(NSString *)typeURLPrefix
+                         error:(NSError **)errorPtr {
+  return [[[self alloc] initWithMessage:message
+                          typeURLPrefix:typeURLPrefix
+                                  error:errorPtr] autorelease];
+}
+
+- (instancetype)initWithMessage:(GPBMessage *)message
+                          error:(NSError **)errorPtr {
+  return [self initWithMessage:message
+                 typeURLPrefix:kTypePrefixGoogleApisCom
+                         error:errorPtr];
+}
+
+- (instancetype)initWithMessage:(GPBMessage *)message
+                  typeURLPrefix:(NSString *)typeURLPrefix
+                          error:(NSError **)errorPtr {
+  self = [self init];
+  if (self) {
+    if (![self packWithMessage:message
+                 typeURLPrefix:typeURLPrefix
+                         error:errorPtr]) {
+      [self release];
+      self = nil;
+    }
+  }
+  return self;
+}
+
+- (BOOL)packWithMessage:(GPBMessage *)message
+                  error:(NSError **)errorPtr {
+  return [self packWithMessage:message
+                 typeURLPrefix:kTypePrefixGoogleApisCom
+                         error:errorPtr];
+}
+
+- (BOOL)packWithMessage:(GPBMessage *)message
+          typeURLPrefix:(NSString *)typeURLPrefix
+                  error:(NSError **)errorPtr {
+  NSString *fullName = [message descriptor].fullName;
+  if (fullName.length == 0) {
+    if (errorPtr) {
+      *errorPtr =
+          [NSError errorWithDomain:GPBWellKnownTypesErrorDomain
+                              code:GPBWellKnownTypesErrorCodeFailedToComputeTypeURL
+                          userInfo:nil];
+    }
+    return NO;
+  }
+  if (errorPtr) {
+    *errorPtr = nil;
+  }
+  self.typeURL = BuildTypeURL(typeURLPrefix, fullName);
+  self.value = message.data;
+  return YES;
+}
+
+- (GPBMessage *)unpackMessageClass:(Class)messageClass
+                             error:(NSError **)errorPtr {
+  NSString *fullName = [messageClass descriptor].fullName;
+  if (fullName.length == 0) {
+    if (errorPtr) {
+      *errorPtr =
+          [NSError errorWithDomain:GPBWellKnownTypesErrorDomain
+                              code:GPBWellKnownTypesErrorCodeFailedToComputeTypeURL
+                      userInfo:nil];
+    }
+    return nil;
+  }
+
+  NSString *expectedFullName = ParseTypeFromURL(self.typeURL);
+  if ((expectedFullName == nil) || ![expectedFullName isEqual:fullName]) {
+    if (errorPtr) {
+      *errorPtr =
+          [NSError errorWithDomain:GPBWellKnownTypesErrorDomain
+                              code:GPBWellKnownTypesErrorCodeTypeURLMismatch
+                          userInfo:nil];
+    }
+    return nil;
+  }
+
+  // Any is proto3, which means no extensions, so this assumes anything put
+  // within an any also won't need extensions. A second helper could be added
+  // if needed.
+  return [messageClass parseFromData:self.value
+                               error:errorPtr];
+}
+
+@end
diff --git a/objectivec/Tests/GPBDescriptorTests.m b/objectivec/Tests/GPBDescriptorTests.m
index 74e3172..1e1c3de 100644
--- a/objectivec/Tests/GPBDescriptorTests.m
+++ b/objectivec/Tests/GPBDescriptorTests.m
@@ -34,12 +34,41 @@
 
 #import "GPBDescriptor.h"
 #import "google/protobuf/Unittest.pbobjc.h"
+#import "google/protobuf/UnittestObjc.pbobjc.h"
+#import "google/protobuf/Descriptor.pbobjc.h"
 
 @interface DescriptorTests : GPBTestCase
 @end
 
 @implementation DescriptorTests
 
+- (void)testDescriptor_containingType {
+  GPBDescriptor *testAllTypesDesc = [TestAllTypes descriptor];
+  GPBDescriptor *nestedMessageDesc = [TestAllTypes_NestedMessage descriptor];
+  XCTAssertNil(testAllTypesDesc.containingType);
+  XCTAssertNotNil(nestedMessageDesc.containingType);
+  XCTAssertEqual(nestedMessageDesc.containingType, testAllTypesDesc);  // Ptr comparison
+}
+
+- (void)testDescriptor_fullName {
+  GPBDescriptor *testAllTypesDesc = [TestAllTypes descriptor];
+  XCTAssertEqualObjects(testAllTypesDesc.fullName, @"protobuf_unittest.TestAllTypes");
+  GPBDescriptor *nestedMessageDesc = [TestAllTypes_NestedMessage descriptor];
+  XCTAssertEqualObjects(nestedMessageDesc.fullName, @"protobuf_unittest.TestAllTypes.NestedMessage");
+
+  // Prefixes removed.
+  GPBDescriptor *descDesc = [GPBDescriptorProto descriptor];
+  XCTAssertEqualObjects(descDesc.fullName, @"google.protobuf.DescriptorProto");
+  GPBDescriptor *descExtRngDesc = [GPBDescriptorProto_ExtensionRange descriptor];
+  XCTAssertEqualObjects(descExtRngDesc.fullName, @"google.protobuf.DescriptorProto.ExtensionRange");
+
+  // Things that get "_Class" added.
+  GPBDescriptor *pointDesc = [Point_Class descriptor];
+  XCTAssertEqualObjects(pointDesc.fullName, @"protobuf_unittest.Point");
+  GPBDescriptor *pointRectDesc = [Point_Rect descriptor];
+  XCTAssertEqualObjects(pointRectDesc.fullName, @"protobuf_unittest.Point.Rect");
+}
+
 - (void)testFieldDescriptor {
   GPBDescriptor *descriptor = [TestAllTypes descriptor];
 
diff --git a/objectivec/Tests/GPBUnittestProtos.m b/objectivec/Tests/GPBUnittestProtos.m
index 7b938e7..8d2948b 100644
--- a/objectivec/Tests/GPBUnittestProtos.m
+++ b/objectivec/Tests/GPBUnittestProtos.m
@@ -36,6 +36,7 @@
 // a descriptor as it doesn't use the classes/enums.
 #import "google/protobuf/Descriptor.pbobjc.m"
 
+#import "google/protobuf/AnyTest.pbobjc.m"
 #import "google/protobuf/MapProto2Unittest.pbobjc.m"
 #import "google/protobuf/MapUnittest.pbobjc.m"
 #import "google/protobuf/Unittest.pbobjc.m"
diff --git a/objectivec/Tests/GPBWellKnownTypesTest.m b/objectivec/Tests/GPBWellKnownTypesTest.m
index 78f4e63..041841d 100644
--- a/objectivec/Tests/GPBWellKnownTypesTest.m
+++ b/objectivec/Tests/GPBWellKnownTypesTest.m
@@ -32,6 +32,8 @@
 
 #import <XCTest/XCTest.h>
 
+#import "google/protobuf/AnyTest.pbobjc.h"
+
 // A basically random interval into the future for testing with.
 static const NSTimeInterval kFutureOffsetInterval = 15000;
 
@@ -99,4 +101,58 @@
   [duration2 release];
 }
 
+- (void)testAnyHelpers {
+
+  // Set and extract covers most of the code.
+
+  TestAny *subMessage = [TestAny message];
+  subMessage.int32Value = 12345;
+  TestAny *message = [TestAny message];
+  NSError *err = nil;
+  message.anyValue = [GPBAny anyWithMessage:subMessage error:&err];
+  XCTAssertNil(err);
+
+  NSData *data = message.data;
+  XCTAssertNotNil(data);
+
+  TestAny *message2 = [TestAny parseFromData:data error:&err];
+  XCTAssertNil(err);
+  XCTAssertNotNil(message2);
+  XCTAssertTrue(message2.hasAnyValue);
+
+  TestAny *subMessage2 =
+      (TestAny *)[message.anyValue unpackMessageClass:[TestAny class]
+                                                error:&err];
+  XCTAssertNil(err);
+  XCTAssertNotNil(subMessage2);
+  XCTAssertEqual(subMessage2.int32Value, 12345);
+
+  // NULL errorPtr in the two calls.
+
+  message.anyValue = [GPBAny anyWithMessage:subMessage error:NULL];
+  NSData *data2 = message.data;
+  XCTAssertEqualObjects(data2, data);
+
+  TestAny *subMessage3 =
+      (TestAny *)[message.anyValue unpackMessageClass:[TestAny class]
+                                                error:NULL];
+  XCTAssertNotNil(subMessage3);
+  XCTAssertEqualObjects(subMessage2, subMessage3);
+
+  // Try to extract wrong type.
+
+  GPBTimestamp *wrongMessage =
+      (GPBTimestamp *)[message.anyValue unpackMessageClass:[GPBTimestamp class]
+                                                     error:&err];
+  XCTAssertNotNil(err);
+  XCTAssertNil(wrongMessage);
+  XCTAssertEqualObjects(err.domain, GPBWellKnownTypesErrorDomain);
+  XCTAssertEqual(err.code, GPBWellKnownTypesErrorCodeTypeURLMismatch);
+
+  wrongMessage =
+      (GPBTimestamp *)[message.anyValue unpackMessageClass:[GPBTimestamp class]
+                                                     error:NULL];
+  XCTAssertNil(wrongMessage);
+}
+
 @end
diff --git a/objectivec/google/protobuf/Any.pbobjc.h b/objectivec/google/protobuf/Any.pbobjc.h
index 842052f..b88b786 100644
--- a/objectivec/google/protobuf/Any.pbobjc.h
+++ b/objectivec/google/protobuf/Any.pbobjc.h
@@ -13,7 +13,7 @@
  #import "GPBProtocolBuffers.h"
 #endif
 
-#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30001
+#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30002
 #error This file was generated by a different version of protoc which is incompatible with your Protocol Buffer library sources.
 #endif
 
diff --git a/objectivec/google/protobuf/Any.pbobjc.m b/objectivec/google/protobuf/Any.pbobjc.m
index deaedc1..50448cb 100644
--- a/objectivec/google/protobuf/Any.pbobjc.m
+++ b/objectivec/google/protobuf/Any.pbobjc.m
@@ -41,6 +41,7 @@
   if (!descriptor) {
     GPBDebugCheckRuntimeVersion();
     descriptor = [[GPBFileDescriptor alloc] initWithPackage:@"google.protobuf"
+                                                 objcPrefix:@"GPB"
                                                      syntax:GPBFileSyntaxProto3];
   }
   return descriptor;
diff --git a/objectivec/google/protobuf/Api.pbobjc.h b/objectivec/google/protobuf/Api.pbobjc.h
index 182e866..3750e09 100644
--- a/objectivec/google/protobuf/Api.pbobjc.h
+++ b/objectivec/google/protobuf/Api.pbobjc.h
@@ -13,7 +13,7 @@
  #import "GPBProtocolBuffers.h"
 #endif
 
-#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30001
+#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30002
 #error This file was generated by a different version of protoc which is incompatible with your Protocol Buffer library sources.
 #endif
 
diff --git a/objectivec/google/protobuf/Api.pbobjc.m b/objectivec/google/protobuf/Api.pbobjc.m
index e73ecf8..5736c81 100644
--- a/objectivec/google/protobuf/Api.pbobjc.m
+++ b/objectivec/google/protobuf/Api.pbobjc.m
@@ -45,6 +45,7 @@
   if (!descriptor) {
     GPBDebugCheckRuntimeVersion();
     descriptor = [[GPBFileDescriptor alloc] initWithPackage:@"google.protobuf"
+                                                 objcPrefix:@"GPB"
                                                      syntax:GPBFileSyntaxProto3];
   }
   return descriptor;
diff --git a/objectivec/google/protobuf/Duration.pbobjc.h b/objectivec/google/protobuf/Duration.pbobjc.h
index fa91e22..090eb00 100644
--- a/objectivec/google/protobuf/Duration.pbobjc.h
+++ b/objectivec/google/protobuf/Duration.pbobjc.h
@@ -13,7 +13,7 @@
  #import "GPBProtocolBuffers.h"
 #endif
 
-#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30001
+#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30002
 #error This file was generated by a different version of protoc which is incompatible with your Protocol Buffer library sources.
 #endif
 
diff --git a/objectivec/google/protobuf/Duration.pbobjc.m b/objectivec/google/protobuf/Duration.pbobjc.m
index 79fbe00..7079276 100644
--- a/objectivec/google/protobuf/Duration.pbobjc.m
+++ b/objectivec/google/protobuf/Duration.pbobjc.m
@@ -41,6 +41,7 @@
   if (!descriptor) {
     GPBDebugCheckRuntimeVersion();
     descriptor = [[GPBFileDescriptor alloc] initWithPackage:@"google.protobuf"
+                                                 objcPrefix:@"GPB"
                                                      syntax:GPBFileSyntaxProto3];
   }
   return descriptor;
diff --git a/objectivec/google/protobuf/Empty.pbobjc.h b/objectivec/google/protobuf/Empty.pbobjc.h
index 4d36174..e0ed3e1 100644
--- a/objectivec/google/protobuf/Empty.pbobjc.h
+++ b/objectivec/google/protobuf/Empty.pbobjc.h
@@ -13,7 +13,7 @@
  #import "GPBProtocolBuffers.h"
 #endif
 
-#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30001
+#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30002
 #error This file was generated by a different version of protoc which is incompatible with your Protocol Buffer library sources.
 #endif
 
diff --git a/objectivec/google/protobuf/Empty.pbobjc.m b/objectivec/google/protobuf/Empty.pbobjc.m
index 83cede2..f4f21f6 100644
--- a/objectivec/google/protobuf/Empty.pbobjc.m
+++ b/objectivec/google/protobuf/Empty.pbobjc.m
@@ -41,6 +41,7 @@
   if (!descriptor) {
     GPBDebugCheckRuntimeVersion();
     descriptor = [[GPBFileDescriptor alloc] initWithPackage:@"google.protobuf"
+                                                 objcPrefix:@"GPB"
                                                      syntax:GPBFileSyntaxProto3];
   }
   return descriptor;
diff --git a/objectivec/google/protobuf/FieldMask.pbobjc.h b/objectivec/google/protobuf/FieldMask.pbobjc.h
index 491463f..14ed537 100644
--- a/objectivec/google/protobuf/FieldMask.pbobjc.h
+++ b/objectivec/google/protobuf/FieldMask.pbobjc.h
@@ -13,7 +13,7 @@
  #import "GPBProtocolBuffers.h"
 #endif
 
-#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30001
+#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30002
 #error This file was generated by a different version of protoc which is incompatible with your Protocol Buffer library sources.
 #endif
 
diff --git a/objectivec/google/protobuf/FieldMask.pbobjc.m b/objectivec/google/protobuf/FieldMask.pbobjc.m
index 906e3cb..d4cceee 100644
--- a/objectivec/google/protobuf/FieldMask.pbobjc.m
+++ b/objectivec/google/protobuf/FieldMask.pbobjc.m
@@ -41,6 +41,7 @@
   if (!descriptor) {
     GPBDebugCheckRuntimeVersion();
     descriptor = [[GPBFileDescriptor alloc] initWithPackage:@"google.protobuf"
+                                                 objcPrefix:@"GPB"
                                                      syntax:GPBFileSyntaxProto3];
   }
   return descriptor;
diff --git a/objectivec/google/protobuf/SourceContext.pbobjc.h b/objectivec/google/protobuf/SourceContext.pbobjc.h
index d945005..417562c 100644
--- a/objectivec/google/protobuf/SourceContext.pbobjc.h
+++ b/objectivec/google/protobuf/SourceContext.pbobjc.h
@@ -13,7 +13,7 @@
  #import "GPBProtocolBuffers.h"
 #endif
 
-#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30001
+#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30002
 #error This file was generated by a different version of protoc which is incompatible with your Protocol Buffer library sources.
 #endif
 
diff --git a/objectivec/google/protobuf/SourceContext.pbobjc.m b/objectivec/google/protobuf/SourceContext.pbobjc.m
index 5c6ca6c..d80231a 100644
--- a/objectivec/google/protobuf/SourceContext.pbobjc.m
+++ b/objectivec/google/protobuf/SourceContext.pbobjc.m
@@ -41,6 +41,7 @@
   if (!descriptor) {
     GPBDebugCheckRuntimeVersion();
     descriptor = [[GPBFileDescriptor alloc] initWithPackage:@"google.protobuf"
+                                                 objcPrefix:@"GPB"
                                                      syntax:GPBFileSyntaxProto3];
   }
   return descriptor;
diff --git a/objectivec/google/protobuf/Struct.pbobjc.h b/objectivec/google/protobuf/Struct.pbobjc.h
index a5b31cd..163b39b 100644
--- a/objectivec/google/protobuf/Struct.pbobjc.h
+++ b/objectivec/google/protobuf/Struct.pbobjc.h
@@ -13,7 +13,7 @@
  #import "GPBProtocolBuffers.h"
 #endif
 
-#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30001
+#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30002
 #error This file was generated by a different version of protoc which is incompatible with your Protocol Buffer library sources.
 #endif
 
diff --git a/objectivec/google/protobuf/Struct.pbobjc.m b/objectivec/google/protobuf/Struct.pbobjc.m
index 55c135e..02f7d24 100644
--- a/objectivec/google/protobuf/Struct.pbobjc.m
+++ b/objectivec/google/protobuf/Struct.pbobjc.m
@@ -42,6 +42,7 @@
   if (!descriptor) {
     GPBDebugCheckRuntimeVersion();
     descriptor = [[GPBFileDescriptor alloc] initWithPackage:@"google.protobuf"
+                                                 objcPrefix:@"GPB"
                                                      syntax:GPBFileSyntaxProto3];
   }
   return descriptor;
diff --git a/objectivec/google/protobuf/Timestamp.pbobjc.h b/objectivec/google/protobuf/Timestamp.pbobjc.h
index ebfa670..094e9b6 100644
--- a/objectivec/google/protobuf/Timestamp.pbobjc.h
+++ b/objectivec/google/protobuf/Timestamp.pbobjc.h
@@ -13,7 +13,7 @@
  #import "GPBProtocolBuffers.h"
 #endif
 
-#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30001
+#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30002
 #error This file was generated by a different version of protoc which is incompatible with your Protocol Buffer library sources.
 #endif
 
diff --git a/objectivec/google/protobuf/Timestamp.pbobjc.m b/objectivec/google/protobuf/Timestamp.pbobjc.m
index 5e4d5cc..7c57b4f 100644
--- a/objectivec/google/protobuf/Timestamp.pbobjc.m
+++ b/objectivec/google/protobuf/Timestamp.pbobjc.m
@@ -41,6 +41,7 @@
   if (!descriptor) {
     GPBDebugCheckRuntimeVersion();
     descriptor = [[GPBFileDescriptor alloc] initWithPackage:@"google.protobuf"
+                                                 objcPrefix:@"GPB"
                                                      syntax:GPBFileSyntaxProto3];
   }
   return descriptor;
diff --git a/objectivec/google/protobuf/Type.pbobjc.h b/objectivec/google/protobuf/Type.pbobjc.h
index 0541195..da923c3 100644
--- a/objectivec/google/protobuf/Type.pbobjc.h
+++ b/objectivec/google/protobuf/Type.pbobjc.h
@@ -13,7 +13,7 @@
  #import "GPBProtocolBuffers.h"
 #endif
 
-#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30001
+#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30002
 #error This file was generated by a different version of protoc which is incompatible with your Protocol Buffer library sources.
 #endif
 
diff --git a/objectivec/google/protobuf/Type.pbobjc.m b/objectivec/google/protobuf/Type.pbobjc.m
index b48f4d0..dfe1186 100644
--- a/objectivec/google/protobuf/Type.pbobjc.m
+++ b/objectivec/google/protobuf/Type.pbobjc.m
@@ -45,6 +45,7 @@
   if (!descriptor) {
     GPBDebugCheckRuntimeVersion();
     descriptor = [[GPBFileDescriptor alloc] initWithPackage:@"google.protobuf"
+                                                 objcPrefix:@"GPB"
                                                      syntax:GPBFileSyntaxProto3];
   }
   return descriptor;
diff --git a/objectivec/google/protobuf/Wrappers.pbobjc.h b/objectivec/google/protobuf/Wrappers.pbobjc.h
index e397c48..2bf6fd2 100644
--- a/objectivec/google/protobuf/Wrappers.pbobjc.h
+++ b/objectivec/google/protobuf/Wrappers.pbobjc.h
@@ -13,7 +13,7 @@
  #import "GPBProtocolBuffers.h"
 #endif
 
-#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30001
+#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30002
 #error This file was generated by a different version of protoc which is incompatible with your Protocol Buffer library sources.
 #endif
 
diff --git a/objectivec/google/protobuf/Wrappers.pbobjc.m b/objectivec/google/protobuf/Wrappers.pbobjc.m
index ebf8e22..73a1384 100644
--- a/objectivec/google/protobuf/Wrappers.pbobjc.m
+++ b/objectivec/google/protobuf/Wrappers.pbobjc.m
@@ -41,6 +41,7 @@
   if (!descriptor) {
     GPBDebugCheckRuntimeVersion();
     descriptor = [[GPBFileDescriptor alloc] initWithPackage:@"google.protobuf"
+                                                 objcPrefix:@"GPB"
                                                      syntax:GPBFileSyntaxProto3];
   }
   return descriptor;
diff --git a/src/google/protobuf/compiler/objectivec/objectivec_file.cc b/src/google/protobuf/compiler/objectivec/objectivec_file.cc
index f70d4d5..685ed56 100644
--- a/src/google/protobuf/compiler/objectivec/objectivec_file.cc
+++ b/src/google/protobuf/compiler/objectivec/objectivec_file.cc
@@ -53,7 +53,7 @@
 // This is also found in GPBBootstrap.h, and needs to be kept in sync.  It
 // is the version check done to ensure generated code works with the current
 // runtime being used.
-const int32 GOOGLE_PROTOBUF_OBJC_GEN_VERSION = 30001;
+const int32 GOOGLE_PROTOBUF_OBJC_GEN_VERSION = 30002;
 
 const char* kHeaderExtension = ".pbobjc.h";
 
@@ -463,19 +463,22 @@
 
   // File descriptor only needed if there are messages to use it.
   if (message_generators_.size() > 0) {
-    string syntax;
+    map<string, string> vars;
+    vars["root_class_name"] = root_class_name_;
+    vars["package"] = file_->package();
+    vars["objc_prefix"] = FileClassPrefix(file_);
     switch (file_->syntax()) {
       case FileDescriptor::SYNTAX_UNKNOWN:
-        syntax = "GPBFileSyntaxUnknown";
+        vars["syntax"] = "GPBFileSyntaxUnknown";
         break;
       case FileDescriptor::SYNTAX_PROTO2:
-        syntax = "GPBFileSyntaxProto2";
+        vars["syntax"] = "GPBFileSyntaxProto2";
         break;
       case FileDescriptor::SYNTAX_PROTO3:
-        syntax = "GPBFileSyntaxProto3";
+        vars["syntax"] = "GPBFileSyntaxProto3";
         break;
     }
-    printer->Print(
+    printer->Print(vars,
         "#pragma mark - $root_class_name$_FileDescriptor\n"
         "\n"
         "static GPBFileDescriptor *$root_class_name$_FileDescriptor(void) {\n"
@@ -483,16 +486,24 @@
         "  // about thread safety of the singleton.\n"
         "  static GPBFileDescriptor *descriptor = NULL;\n"
         "  if (!descriptor) {\n"
-        "    GPBDebugCheckRuntimeVersion();\n"
-        "    descriptor = [[GPBFileDescriptor alloc] initWithPackage:@\"$package$\"\n"
-        "                                                     syntax:$syntax$];\n"
+        "    GPBDebugCheckRuntimeVersion();\n");
+    if (vars["objc_prefix"].size() > 0) {
+      printer->Print(
+          vars,
+          "    descriptor = [[GPBFileDescriptor alloc] initWithPackage:@\"$package$\"\n"
+          "                                                 objcPrefix:@\"$objc_prefix$\"\n"
+          "                                                     syntax:$syntax$];\n");
+    } else {
+      printer->Print(
+          vars,
+          "    descriptor = [[GPBFileDescriptor alloc] initWithPackage:@\"$package$\"\n"
+          "                                                     syntax:$syntax$];\n");
+    }
+    printer->Print(
         "  }\n"
         "  return descriptor;\n"
         "}\n"
-        "\n",
-        "root_class_name", root_class_name_,
-        "package", file_->package(),
-        "syntax", syntax);
+        "\n");
   }
 
   for (vector<EnumGenerator *>::iterator iter = enum_generators_.begin();
diff --git a/src/google/protobuf/compiler/objectivec/objectivec_helpers.cc b/src/google/protobuf/compiler/objectivec/objectivec_helpers.cc
index 847be98..2fe0016 100644
--- a/src/google/protobuf/compiler/objectivec/objectivec_helpers.cc
+++ b/src/google/protobuf/compiler/objectivec/objectivec_helpers.cc
@@ -210,10 +210,14 @@
 hash_set<string> kReservedWords =
     MakeWordsMap(kReservedWordList, GOOGLE_ARRAYSIZE(kReservedWordList));
 
-string SanitizeNameForObjC(const string& input, const string& extension) {
+string SanitizeNameForObjC(const string& input,
+                           const string& extension,
+                           string* out_suffix_added) {
   if (kReservedWords.count(input) > 0) {
+    if (out_suffix_added) *out_suffix_added = extension;
     return input + extension;
   }
+  if (out_suffix_added) out_suffix_added->clear();
   return input;
 }
 
@@ -308,6 +312,12 @@
   return basename;
 }
 
+string FileClassPrefix(const FileDescriptor* file) {
+  // Default is empty string, no need to check has_objc_class_prefix.
+  string result = file->options().objc_class_prefix();
+  return result;
+}
+
 string FilePath(const FileDescriptor* file) {
   string output;
   string basename;
@@ -338,19 +348,13 @@
   return output;
 }
 
-string FileClassPrefix(const FileDescriptor* file) {
-  // Default is empty string, no need to check has_objc_class_prefix.
-  string result = file->options().objc_class_prefix();
-  return result;
-}
-
 string FileClassName(const FileDescriptor* file) {
   string name = FileClassPrefix(file);
   name += UnderscoresToCamelCase(StripProto(BaseFileName(file)), true);
   name += "Root";
   // There aren't really any reserved words that end in "Root", but playing
   // it safe and checking.
-  return SanitizeNameForObjC(name, "_RootClass");
+  return SanitizeNameForObjC(name, "_RootClass", NULL);
 }
 
 string ClassNameWorker(const Descriptor* descriptor) {
@@ -372,11 +376,15 @@
 }
 
 string ClassName(const Descriptor* descriptor) {
+  return ClassName(descriptor, NULL);
+}
+
+string ClassName(const Descriptor* descriptor, string* out_suffix_added) {
   // 1. Message names are used as is (style calls for CamelCase, trust it).
   // 2. Check for reserved word at the very end and then suffix things.
   string prefix = FileClassPrefix(descriptor->file());
   string name = ClassNameWorker(descriptor);
-  return SanitizeNameForObjC(prefix + name, "_Class");
+  return SanitizeNameForObjC(prefix + name, "_Class", out_suffix_added);
 }
 
 string EnumName(const EnumDescriptor* descriptor) {
@@ -390,7 +398,7 @@
   //    yields Fixed_Class, Fixed_Size.
   string name = FileClassPrefix(descriptor->file());
   name += ClassNameWorker(descriptor);
-  return SanitizeNameForObjC(name, "_Enum");
+  return SanitizeNameForObjC(name, "_Enum", NULL);
 }
 
 string EnumValueName(const EnumValueDescriptor* descriptor) {
@@ -405,7 +413,7 @@
   const string& name = class_name + "_" + value_str;
   // There aren't really any reserved words with an underscore and a leading
   // capital letter, but playing it safe and checking.
-  return SanitizeNameForObjC(name, "_Value");
+  return SanitizeNameForObjC(name, "_Value", NULL);
 }
 
 string EnumValueShortName(const EnumValueDescriptor* descriptor) {
@@ -442,7 +450,7 @@
 string ExtensionMethodName(const FieldDescriptor* descriptor) {
   const string& name = NameFromFieldDescriptor(descriptor);
   const string& result = UnderscoresToCamelCase(name, false);
-  return SanitizeNameForObjC(result, "_Extension");
+  return SanitizeNameForObjC(result, "_Extension", NULL);
 }
 
 string FieldName(const FieldDescriptor* field) {
@@ -457,7 +465,7 @@
       result += "_p";
     }
   }
-  return SanitizeNameForObjC(result, "_p");
+  return SanitizeNameForObjC(result, "_p", NULL);
 }
 
 string FieldNameCapitalized(const FieldDescriptor* field) {
diff --git a/src/google/protobuf/compiler/objectivec/objectivec_helpers.h b/src/google/protobuf/compiler/objectivec/objectivec_helpers.h
index b05983d..022b7a1 100644
--- a/src/google/protobuf/compiler/objectivec/objectivec_helpers.h
+++ b/src/google/protobuf/compiler/objectivec/objectivec_helpers.h
@@ -67,6 +67,9 @@
 // handling under ARC.
 bool IsInitName(const string& name);
 
+// Gets the objc_class_prefix.
+string FileClassPrefix(const FileDescriptor* file);
+
 // Gets the path of the file we're going to generate (sans the .pb.h
 // extension).  The path will be dependent on the objectivec package
 // declared in the proto package.
@@ -83,6 +86,7 @@
 // These return the fully-qualified class name corresponding to the given
 // descriptor.
 string ClassName(const Descriptor* descriptor);
+string ClassName(const Descriptor* descriptor, string* out_suffix_added);
 string EnumName(const EnumDescriptor* descriptor);
 
 // Returns the fully-qualified name of the enum value corresponding to the
diff --git a/src/google/protobuf/compiler/objectivec/objectivec_message.cc b/src/google/protobuf/compiler/objectivec/objectivec_message.cc
index 822da89..7c5fe31 100644
--- a/src/google/protobuf/compiler/objectivec/objectivec_message.cc
+++ b/src/google/protobuf/compiler/objectivec/objectivec_message.cc
@@ -579,6 +579,19 @@
           "    [localDescriptor setupExtensionRanges:ranges\n"
           "                                    count:(uint32_t)(sizeof(ranges) / sizeof(GPBExtensionRange))];\n");
     }
+    if (descriptor_->containing_type() != NULL) {
+      string parent_class_name = ClassName(descriptor_->containing_type());
+      printer->Print(
+          "    [localDescriptor setupContainingMessageClassName:GPBStringifySymbol($parent_name$)];\n",
+          "parent_name", parent_class_name);
+    }
+    string suffix_added;
+    ClassName(descriptor_, &suffix_added);
+    if (suffix_added.size() > 0) {
+      printer->Print(
+          "    [localDescriptor setupMessageClassNameSuffix:@\"$suffix$\"];\n",
+          "suffix", suffix_added);
+    }
     printer->Print(
         "    NSAssert(descriptor == nil, @\"Startup recursed!\");\n"
         "    descriptor = localDescriptor;\n"