New options now work fine.
diff --git a/src/ProtoGen.Test/ProtoGen.Test.csproj b/src/ProtoGen.Test/ProtoGen.Test.csproj
index a133449..426431b 100644
--- a/src/ProtoGen.Test/ProtoGen.Test.csproj
+++ b/src/ProtoGen.Test/ProtoGen.Test.csproj
@@ -45,7 +45,6 @@
   </ItemGroup>
   <ItemGroup>
     <Compile Include="DependencyResolutionTest.cs" />
-    <Compile Include="DescriptorUtilTest.cs" />
     <Compile Include="GeneratorTest.cs" />
     <Compile Include="Properties\AssemblyInfo.cs" />
   </ItemGroup>
diff --git a/src/ProtoGen/ExtensionGenerator.cs b/src/ProtoGen/ExtensionGenerator.cs
index d1acacd..2f6876c 100644
--- a/src/ProtoGen/ExtensionGenerator.cs
+++ b/src/ProtoGen/ExtensionGenerator.cs
@@ -9,7 +9,7 @@
     }
 
     public void Generate(TextGenerator writer) {
-      string name = NameHelpers.UnderscoresToPascalCase(GetFieldName(Descriptor));
+      string name = Descriptor.CSharpOptions.PropertyName;
 
       string type;
       switch (Descriptor.MappedType) {
diff --git a/src/ProtoGen/FieldGeneratorBase.cs b/src/ProtoGen/FieldGeneratorBase.cs
index a6e086e..d20745a 100644
--- a/src/ProtoGen/FieldGeneratorBase.cs
+++ b/src/ProtoGen/FieldGeneratorBase.cs
@@ -73,17 +73,9 @@
       }
     }
 
-    /// <summary>
-    /// Usually the same as CapitalizedName, except when the enclosing type has the same name,
-    /// in which case an underscore is appended.
-    /// </summary>
     protected string PropertyName {
       get {
-        string ret = CapitalizedName;
-        if (ret == Descriptor.ContainingType.Name) {
-          ret += "_";
-        }
-        return ret;
+        return Descriptor.CSharpOptions.PropertyName;
       }
     }
 
diff --git a/src/ProtoGen/Generator.cs b/src/ProtoGen/Generator.cs
index f7a82cc..828b610 100644
--- a/src/ProtoGen/Generator.cs
+++ b/src/ProtoGen/Generator.cs
@@ -30,8 +30,8 @@
       foreach (string inputFile in options.InputFiles) {
         FileDescriptorSet descriptorProtos;       
         ExtensionRegistry extensionRegistry = ExtensionRegistry.CreateInstance();
-        extensionRegistry.Add(CSharpFileOptions.CSharpOptions);
-        extensionRegistry.Add(CSharpFieldOptions.CSharpOptions);
+        extensionRegistry.Add(CSharpOptions.CSharpFileOptions);
+        extensionRegistry.Add(CSharpOptions.CSharpFieldOptions);
         using (Stream inputStream = File.OpenRead(inputFile)) {
           descriptorProtos = FileDescriptorSet.ParseFrom(inputStream, extensionRegistry);
         }
diff --git a/src/ProtoGen.Test/DescriptorUtilTest.cs b/src/ProtocolBuffers.Test/CSharpOptionsTest.cs
similarity index 69%
rename from src/ProtoGen.Test/DescriptorUtilTest.cs
rename to src/ProtocolBuffers.Test/CSharpOptionsTest.cs
index 2eb60ef..d22f99d 100644
--- a/src/ProtoGen.Test/DescriptorUtilTest.cs
+++ b/src/ProtocolBuffers.Test/CSharpOptionsTest.cs
@@ -1,69 +1,70 @@
-using Google.ProtocolBuffers.DescriptorProtos;
+using Google.ProtocolBuffers.DescriptorProtos;
 using Google.ProtocolBuffers.Descriptors;
 using NUnit.Framework;
 
-namespace Google.ProtocolBuffers.ProtoGen {
+namespace Google.ProtocolBuffers {
   [TestFixture]
   public class DescriptorUtilTest {
-    /* FIXME: Move these around!
     [Test]
     public void ExplicitNamespace() {
       FileDescriptorProto proto = new FileDescriptorProto.Builder {
-        Name = "x", Package = "pack", Options = new FileOptions.Builder().SetExtension(CSharpOptions.CSharpNamespace, "Foo.Bar").Build()
+        Name = "x", Package = "pack", Options = new FileOptions.Builder().SetExtension(CSharpOptions.CSharpFileOptions,
+          new CSharpFileOptions.Builder { Namespace = "Foo.Bar" }.Build()).Build()
       }.Build();
       FileDescriptor descriptor = FileDescriptor.BuildFrom(proto, null);
-      Assert.AreEqual("Foo.Bar", DescriptorUtil.GetNamespace(descriptor));
+      Assert.AreEqual("Foo.Bar", descriptor.CSharpOptions.Namespace);
     }
 
     [Test]
     public void NoNamespaceFallsBackToPackage() {
       FileDescriptorProto proto = new FileDescriptorProto.Builder { Name = "x", Package = "pack" }.Build();
       FileDescriptor descriptor = FileDescriptor.BuildFrom(proto, null);
-      Assert.AreEqual("pack", DescriptorUtil.GetNamespace(descriptor));
+      Assert.AreEqual("pack", descriptor.CSharpOptions.Namespace);
     }
 
     [Test]
     public void NoNamespaceOrPackageFallsBackToEmptyString() {
       FileDescriptorProto proto = new FileDescriptorProto.Builder { Name = "x" }.Build();
       FileDescriptor descriptor = FileDescriptor.BuildFrom(proto, null);
-      Assert.AreEqual("", DescriptorUtil.GetNamespace(descriptor));
+      Assert.AreEqual("", descriptor.CSharpOptions.Namespace);
     }
 
     [Test]
     public void ExplicitlyNamedFileClass() {
       FileDescriptorProto proto = new FileDescriptorProto.Builder {
-        Name = "x", Options = new FileOptions.Builder().SetExtension(CSharpOptions.CSharpUmbrellaClassname, "Foo").Build()
+        Name = "x", Options = new FileOptions.Builder().SetExtension(CSharpOptions.CSharpFileOptions,
+          new CSharpFileOptions.Builder { UmbrellaClassname = "Foo" }.Build()).Build()
       }.Build();
       FileDescriptor descriptor = FileDescriptor.BuildFrom(proto, null);
-      Assert.AreEqual("Foo", DescriptorUtil.GetUmbrellaClassName(descriptor));
+      Assert.AreEqual("Foo", descriptor.CSharpOptions.UmbrellaClassname);
     }
 
     [Test]
     public void ImplicitFileClassWithProtoSuffix() {
       FileDescriptorProto proto = new FileDescriptorProto.Builder { Name = "foo_bar.proto" }.Build();
       FileDescriptor descriptor = FileDescriptor.BuildFrom(proto, null);
-      Assert.AreEqual("FooBar", DescriptorUtil.GetUmbrellaClassName(descriptor));
+      Assert.AreEqual("FooBar", descriptor.CSharpOptions.UmbrellaClassname);
     }
 
     [Test]
     public void ImplicitFileClassWithProtoDevelSuffix() {
       FileDescriptorProto proto = new FileDescriptorProto.Builder { Name = "foo_bar.protodevel" }.Build();
       FileDescriptor descriptor = FileDescriptor.BuildFrom(proto, null);
-      Assert.AreEqual("FooBar", DescriptorUtil.GetUmbrellaClassName(descriptor));
+      Assert.AreEqual("FooBar", descriptor.CSharpOptions.UmbrellaClassname);
     }
 
     [Test]
     public void ImplicitFileClassWithNoSuffix() {
       FileDescriptorProto proto = new FileDescriptorProto.Builder { Name = "foo_bar" }.Build();
       FileDescriptor descriptor = FileDescriptor.BuildFrom(proto, null);
-      Assert.AreEqual("FooBar", DescriptorUtil.GetUmbrellaClassName(descriptor));
+      Assert.AreEqual("FooBar", descriptor.CSharpOptions.UmbrellaClassname);
     }
 
     [Test]
     public void ImplicitFileClassWithDirectoryStructure() {
       FileDescriptorProto proto = new FileDescriptorProto.Builder { Name = "x/y/foo_bar" }.Build();
       FileDescriptor descriptor = FileDescriptor.BuildFrom(proto, null);
-      Assert.AreEqual("FooBar", DescriptorUtil.GetUmbrellaClassName(descriptor));
-    } */
+      Assert.AreEqual("FooBar", descriptor.CSharpOptions.UmbrellaClassname);
+    }
   }
 }
diff --git a/src/ProtocolBuffers.Test/ProtocolBuffers.Test.csproj b/src/ProtocolBuffers.Test/ProtocolBuffers.Test.csproj
index 836ee2d..277348c 100644
--- a/src/ProtocolBuffers.Test/ProtocolBuffers.Test.csproj
+++ b/src/ProtocolBuffers.Test/ProtocolBuffers.Test.csproj
@@ -51,6 +51,7 @@
     <Compile Include="CodedInputStreamTest.cs" />
     <Compile Include="CodedOutputStreamTest.cs" />
     <Compile Include="Collections\PopsicleListTest.cs" />
+    <Compile Include="CSharpOptionsTest.cs" />
     <Compile Include="DescriptorsTest.cs" />
     <Compile Include="DynamicMessageTest.cs" />
     <Compile Include="GeneratedMessageTest.cs" />
diff --git a/src/ProtocolBuffers.Test/TestProtos/___7469.tmp b/src/ProtocolBuffers.Test/TestProtos/___7469.tmp
deleted file mode 100644
index e69de29..0000000
--- a/src/ProtocolBuffers.Test/TestProtos/___7469.tmp
+++ /dev/null
diff --git a/src/ProtocolBuffers/DescriptorProtos/CSharpOptions.cs b/src/ProtocolBuffers/DescriptorProtos/CSharpOptions.cs
index 55a3003..743a0c3 100644
--- a/src/ProtocolBuffers/DescriptorProtos/CSharpOptions.cs
+++ b/src/ProtocolBuffers/DescriptorProtos/CSharpOptions.cs
@@ -16,20 +16,27 @@
         global::System.Convert.FromBase64String(
         "CiRnb29nbGUvcHJvdG9idWYvY3NoYXJwX29wdGlvbnMucHJvdG8SD2dvb2ds" + 
         "ZS5wcm90b2J1ZhogZ29vZ2xlL3Byb3RvYnVmL2Rlc2NyaXB0b3IucHJvdG8i" + 
-        "4wEKEUNTaGFycEZpbGVPcHRpb25zEhEKCW5hbWVzcGFjZRgBIAEoCRIaChJ1" + 
+        "iAEKEUNTaGFycEZpbGVPcHRpb25zEhEKCW5hbWVzcGFjZRgBIAEoCRIaChJ1" + 
         "bWJyZWxsYV9jbGFzc25hbWUYAiABKAkSFgoOcHVibGljX2NsYXNzZXMYAyAB" + 
         "KAgSFgoObXVsdGlwbGVfZmlsZXMYBCABKAgSFAoMbmVzdF9jbGFzc2VzGAUg" + 
-        "ASgIMlkKDmNzaGFycF9vcHRpb25zEhwuZ29vZ2xlLnByb3RvYnVmLkZpbGVP" + 
-        "cHRpb25zGOgHIAEoCzIiLmdvb2dsZS5wcm90b2J1Zi5DU2hhcnBGaWxlT3B0" + 
-        "aW9ucyKIAQoSQ1NoYXJwRmllbGRPcHRpb25zEhUKDXByb3BlcnR5X25hbWUY" + 
-        "ASABKAkyWwoOY3NoYXJwX29wdGlvbnMSHS5nb29nbGUucHJvdG9idWYuRmll" + 
-        "bGRPcHRpb25zGOgHIAEoCzIjLmdvb2dsZS5wcm90b2J1Zi5DU2hhcnBGaWVs" + 
-        "ZE9wdGlvbnM="),
+        "ASgIIisKEkNTaGFycEZpZWxkT3B0aW9ucxIVCg1wcm9wZXJ0eV9uYW1lGAEg" + 
+        "ASgJOl4KE2NzaGFycF9maWxlX29wdGlvbnMSHC5nb29nbGUucHJvdG9idWYu" + 
+        "RmlsZU9wdGlvbnMY6AcgASgLMiIuZ29vZ2xlLnByb3RvYnVmLkNTaGFycEZp" + 
+        "bGVPcHRpb25zOmEKFGNzaGFycF9maWVsZF9vcHRpb25zEh0uZ29vZ2xlLnBy" + 
+        "b3RvYnVmLkZpZWxkT3B0aW9ucxjoByABKAsyIy5nb29nbGUucHJvdG9idWYu" + 
+        "Q1NoYXJwRmllbGRPcHRpb25z"),
         new pbd::FileDescriptor[] {
           global::Google.ProtocolBuffers.DescriptorProtos.DescriptorProtoFile.Descriptor, 
         });
     #endregion
     
+    #region Extensions
+    public static readonly pb::GeneratedExtensionBase<global::Google.ProtocolBuffers.DescriptorProtos.CSharpFileOptions> CSharpFileOptions =
+        pb::GeneratedSingleExtension<global::Google.ProtocolBuffers.DescriptorProtos.CSharpFileOptions>.CreateInstance(Descriptor.Extensions[0]);
+    public static readonly pb::GeneratedExtensionBase<global::Google.ProtocolBuffers.DescriptorProtos.CSharpFieldOptions> CSharpFieldOptions =
+        pb::GeneratedSingleExtension<global::Google.ProtocolBuffers.DescriptorProtos.CSharpFieldOptions>.CreateInstance(Descriptor.Extensions[1]);
+    #endregion
+    
     #region Static variables
     internal static readonly pbd::MessageDescriptor internal__static_google_protobuf_CSharpFileOptions__Descriptor
         = Descriptor.MessageTypes[0];
@@ -66,8 +73,6 @@
       get { return global::Google.ProtocolBuffers.DescriptorProtos.CSharpOptions.internal__static_google_protobuf_CSharpFileOptions__FieldAccessorTable; }
     }
     
-    public static readonly pb::GeneratedExtensionBase<global::Google.ProtocolBuffers.DescriptorProtos.CSharpFileOptions> CSharpOptions =
-        pb::GeneratedSingleExtension<global::Google.ProtocolBuffers.DescriptorProtos.CSharpFileOptions>.CreateInstance(Descriptor.Extensions[0]);
     private bool hasNamespace;
     private string namespace_ = "";
     public bool HasNamespace {
@@ -293,8 +298,6 @@
       get { return global::Google.ProtocolBuffers.DescriptorProtos.CSharpOptions.internal__static_google_protobuf_CSharpFieldOptions__FieldAccessorTable; }
     }
     
-    public static readonly pb::GeneratedExtensionBase<global::Google.ProtocolBuffers.DescriptorProtos.CSharpFieldOptions> CSharpOptions =
-        pb::GeneratedSingleExtension<global::Google.ProtocolBuffers.DescriptorProtos.CSharpFieldOptions>.CreateInstance(Descriptor.Extensions[0]);
     private bool hasPropertyName;
     private string propertyName_ = "";
     public bool HasPropertyName {
diff --git a/src/ProtocolBuffers/Descriptors/FieldDescriptor.cs b/src/ProtocolBuffers/Descriptors/FieldDescriptor.cs
index 5ff5519..0d0fad7 100644
--- a/src/ProtocolBuffers/Descriptors/FieldDescriptor.cs
+++ b/src/ProtocolBuffers/Descriptors/FieldDescriptor.cs
@@ -50,6 +50,9 @@
     private FieldType fieldType;
     private MappedType mappedType;
 
+    private CSharpFieldOptions csharpFieldOptions;
+    private readonly object optionsLock = new object();
+
     internal FieldDescriptor(FieldDescriptorProto proto, FileDescriptor file,
         MessageDescriptor parent, int index, bool isExtension) 
         : base(proto, file, ComputeFullName(file, parent, proto.Name), index) {
@@ -87,6 +90,31 @@
       file.DescriptorPool.AddSymbol(this);
     }
 
+    private CSharpFieldOptions BuildOrFakeCSharpOptions() {
+      // TODO(jonskeet): Check if we could use FileDescriptorProto.Descriptor.Name - interesting bootstrap issues
+      if (File.Proto.Name == "google/protobuf/csharp_options.proto") {
+        if (Name=="csharp_field_options") {
+          return new CSharpFieldOptions.Builder { PropertyName = "CSharpFieldOptions" }.Build();
+        }
+        if (Name=="csharp_file_options") {
+          return new CSharpFieldOptions.Builder { PropertyName = "CSharpFileOptions" }.Build();
+        }
+      }
+      CSharpFieldOptions.Builder builder = CSharpFieldOptions.CreateBuilder();
+      if (Proto.Options.HasExtension(DescriptorProtos.CSharpOptions.CSharpFieldOptions)) {
+        builder.MergeFrom(Proto.Options.GetExtension(DescriptorProtos.CSharpOptions.CSharpFieldOptions));
+      }
+      if (!builder.HasPropertyName) {
+        string fieldName = FieldType == FieldType.Group ? MessageType.Name : Name;
+        string propertyName = NameHelpers.UnderscoresToPascalCase(fieldName);
+        if (propertyName == ContainingType.Name) {
+          propertyName += "_";
+        }
+        builder.PropertyName = propertyName;
+      }
+      return builder.Build();
+    }
+
     /// <summary>
     /// Maps a field type as included in the .proto file to a FieldType.
     /// </summary>
@@ -191,6 +219,21 @@
     public MessageDescriptor ContainingType {
       get { return containingType; }
     }
+
+    /// <summary>
+    /// Returns the C#-specific options for this file descriptor. This will always be
+    /// completely filled in.
+    /// </summary>
+    public CSharpFieldOptions CSharpOptions {
+      get {
+        lock (optionsLock) {
+          if (csharpFieldOptions == null) {
+            csharpFieldOptions = BuildOrFakeCSharpOptions();
+          }
+        }
+        return csharpFieldOptions;
+      }
+    }
     
     /// <summary>
     /// For extensions defined nested within message types, gets
diff --git a/src/ProtocolBuffers/Descriptors/FileDescriptor.cs b/src/ProtocolBuffers/Descriptors/FileDescriptor.cs
index 79e034a..81c4b79 100644
--- a/src/ProtocolBuffers/Descriptors/FileDescriptor.cs
+++ b/src/ProtocolBuffers/Descriptors/FileDescriptor.cs
@@ -88,8 +88,8 @@
         }.Build();
       }
       CSharpFileOptions.Builder builder = CSharpFileOptions.CreateBuilder();
-      if (proto.Options.HasExtension(CSharpFileOptions.CSharpOptions)) {
-        builder.MergeFrom(proto.Options.GetExtension(CSharpFileOptions.CSharpOptions));
+      if (proto.Options.HasExtension(DescriptorProtos.CSharpOptions.CSharpFileOptions)) {
+        builder.MergeFrom(proto.Options.GetExtension(DescriptorProtos.CSharpOptions.CSharpFileOptions));
       }
       if (!builder.HasNamespace) {
         builder.Namespace = Package;
@@ -128,7 +128,6 @@
     /// <summary>
     /// Returns the C#-specific options for this file descriptor. This will always be
     /// completely filled in.
-    /// FIXME: This isn't thread-safe. Can't do it at construction time due to bootstrapping issues.
     /// </summary>
     public CSharpFileOptions CSharpOptions {
       get {