public object Deserialize(
            BsonReader bsonReader,
            Type classType
        )
        {
            // peek at the discriminator (if present) to see what class to create an instance for
            var discriminator = bsonReader.FindString("_t");
            if (discriminator != null) {
                var actualType = BsonClassMap.LookupTypeByDiscriminator(classType, discriminator);
                if (!classType.IsAssignableFrom(actualType)) {
                    string message = string.Format("Actual type {0} is not assignable to expected type {1}", actualType.FullName, classType.FullName);
                    throw new FileFormatException(message);
                }
                classType = actualType;
            }
            var classMap = BsonClassMap.LookupClassMap(classType);
            if (classMap.IsAnonymous) {
                throw new InvalidOperationException("Anonymous classes cannot be deserialized");
            }
            var obj = Activator.CreateInstance(classType);

            var missingElementPropertyMaps = new List<BsonPropertyMap>(classMap.PropertyMaps); // make a copy!
            bsonReader.ReadStartDocument();
            BsonType bsonType;
            string elementName;
            while (bsonReader.HasElement(out bsonType, out elementName)) {
                if (elementName == "_t") {
                    bsonReader.ReadString("_t"); // skip over discriminator
                    continue;
                }

                var propertyMap = classMap.GetPropertyMapForElement(elementName);
                if (propertyMap != null) {
                    propertyMap.PropertySerializer.DeserializeProperty(bsonReader, obj, propertyMap);
                    missingElementPropertyMaps.Remove(propertyMap);
                } else {
                    if (classMap.IgnoreExtraElements) {
                        bsonReader.SkipElement();
                    } else {
                        string message = string.Format("Unexpected element: {0}", elementName);
                        throw new FileFormatException(message);
                    }
                }
            }
            bsonReader.ReadEndDocument();

            foreach (var propertyMap in missingElementPropertyMaps) {
                if (propertyMap.IsRequired) {
                    string message = string.Format("Required element is missing: {0}", propertyMap.ElementName);
                    throw new BsonSerializationException(message);
                }

                if (propertyMap.HasDefaultValue) {
                    propertyMap.ApplyDefaultValue(obj);
                }
            }

            return obj;
        }