private static void BuildTypeProperties(
            ResourceType parentResourceType,
            ProviderMetadataCacheItem metadataCacheItem,
            Queue<ResourceType> unvisitedTypes)
        {
            Debug.Assert(parentResourceType != null, "parentResourceType != null");
            Debug.Assert(metadataCacheItem != null, "metadataCacheItem != null");
            Debug.Assert(unvisitedTypes != null, "unvisitedTypes != null");

            BindingFlags bindingFlags = WebUtil.PublicInstanceBindingFlags;

            // For non root types, we should only look for properties that are declared for this type
            if (parentResourceType.BaseType != null)
            {
                bindingFlags = bindingFlags | BindingFlags.DeclaredOnly;
            }

            HashSet<string> propertiesToBeIgnored = new HashSet<string>(IgnorePropertiesAttribute.GetProperties(parentResourceType.InstanceType, false /*inherit*/, bindingFlags), StringComparer.Ordinal);
            Debug.Assert(parentResourceType.IsOpenType == false, "ReflectionServiceProvider does not support Open types.");

            HashSet<string> etagPropertyNames = new HashSet<string>(LoadETagProperties(parentResourceType), StringComparer.Ordinal);

            ResourceKeyKind keyKind = (ResourceKeyKind)Int32.MaxValue;
            PropertyInfo[] properties = parentResourceType.InstanceType.GetProperties(bindingFlags);

            // Should not allow System.Object on server
            // The general fix for this bug is to not support any resource type that doesn't have
            // any publically visible properties, including System.object and also custom types which don't have any properties.
            if (!properties.Any() && parentResourceType.BaseType == null)
            {
                throw new NotSupportedException(Strings.ReflectionProvider_ResourceTypeHasNoPublicallyVisibleProperties(parentResourceType.FullName));
            }

            foreach (PropertyInfo property in properties)
            {
                // Ignore the properties which are specified in the IgnoreProperties attribute
                if (propertiesToBeIgnored.Contains(property.Name))
                {
                    continue;
                }

                if (property.CanRead && property.GetIndexParameters().Length == 0)
                {
                    ResourcePropertyKind kind = (ResourcePropertyKind)(-1);
                    ResourceType resourceType;
                    Type resourcePropertyType = property.PropertyType;
                    bool collection = false;

                    if (!TryGetType(metadataCacheItem, resourcePropertyType, out resourceType))
                    {
                        Type collectionType = GetIEnumerableElement(property.PropertyType);
                        if (collectionType != null)
                        {
                            TryGetType(metadataCacheItem, collectionType, out resourceType);

                            // Even if the above method returns false, we should set the
                            // following variable appropriately, so that we can use them below
                            collection = true;
                            resourcePropertyType = collectionType;
                        }
                    }

                    if (resourceType != null)
                    {
                        #region Already Known Type
                        if (resourceType.ResourceTypeKind == ResourceTypeKind.Primitive)
                        {
                            if (collection)
                            {
                                // If it's a collection it can't be a key property (we don't allow collection properties as key)
                                kind = ResourcePropertyKind.Collection;
                            }
                            else
                            {
                                ResourceKeyKind currentKeyKind;
                                if (parentResourceType.BaseType == null && parentResourceType.ResourceTypeKind == ResourceTypeKind.EntityType && IsPropertyKeyProperty(property, out currentKeyKind))
                                {
                                    // Check for key property only on root types, since keys must be defined on the root types
                                    if ((int)currentKeyKind < (int)keyKind)
                                    {
                                        if (parentResourceType.KeyProperties.Count != 0)
                                        {
                                            // Remove the existing property as key property - mark it as non key property
                                            parentResourceType.RemoveKeyProperties();
                                        }

                                        keyKind = currentKeyKind;
                                        kind = ResourcePropertyKind.Key | ResourcePropertyKind.Primitive;
                                    }
                                    else if ((int)currentKeyKind == (int)keyKind)
                                    {
                                        Debug.Assert(currentKeyKind == ResourceKeyKind.AttributedKey, "This is the only way of specifying composite keys");
                                        kind = ResourcePropertyKind.Key | ResourcePropertyKind.Primitive;
                                    }
                                    else
                                    {
                                        kind = ResourcePropertyKind.Primitive;
                                    }
                                }
                                else
                                {
                                    kind = ResourcePropertyKind.Primitive;
                                }
                            }
                        }
                        else if (resourceType.ResourceTypeKind == ResourceTypeKind.ComplexType)
                        {
                            kind = collection ? ResourcePropertyKind.Collection : ResourcePropertyKind.ComplexType;
                        }
                        else if (resourceType.ResourceTypeKind == ResourceTypeKind.EntityType)
                        {
                            kind = collection ? ResourcePropertyKind.ResourceSetReference : ResourcePropertyKind.ResourceReference;
                        }
                        #endregion // Already Known Type
                    }
                    else
                    {
                        resourceType = IsEntityOrComplexType(resourcePropertyType, metadataCacheItem, unvisitedTypes);
                        if (resourceType != null)
                        {
                            if (resourceType.ResourceTypeKind == ResourceTypeKind.ComplexType)
                            {
                                if (collection)
                                {
                                    // For backward compat reasons only look closely on the item type if the property is a collection (IEnumerable<T>) 
                                    // and the T looks like a complex type.
                                    // In that case we used to only allow entity types as T, now with collection properties we also allow primitive and complex types,
                                    //   but we must explicitely disallow collection of collection, that is any T which implements IEnumerable<T>.
                                    // Note that we can't just make IEnumerable<T> not be a complex types since in certain cases we used to recognize it as such
                                    //   and we would break those cases. One example is user registered known types.
                                    Type collectionType = GetIEnumerableElement(resourcePropertyType);
                                    if (collectionType != null)
                                    {
                                        throw new InvalidOperationException(Strings.ReflectionProvider_CollectionOfCollectionProperty(property.Name, parentResourceType.FullName));
                                    }

                                    kind = ResourcePropertyKind.Collection;
                                }
                                else
                                {
                                    kind = ResourcePropertyKind.ComplexType;
                                }
                            }
                            else
                            {
                                Debug.Assert(resourceType.ResourceTypeKind == ResourceTypeKind.EntityType, "Must be an entity type");
                                kind = collection ? ResourcePropertyKind.ResourceSetReference : ResourcePropertyKind.ResourceReference;
                            }
                        }
                    }

                    // if resource type is null OR
                    // if complex type has a property of entity type
                    if (resourceType == null ||
                        (resourceType.ResourceTypeKind == ResourceTypeKind.EntityType && parentResourceType.ResourceTypeKind == ResourceTypeKind.ComplexType))
                    {
                        if (resourceType == null)
                        {
                            // Provide a better error message for collection of collection
                            if (collection && GetIEnumerableElement(resourcePropertyType) != null)
                            {
                                throw new InvalidOperationException(Strings.ReflectionProvider_CollectionOfCollectionProperty(property.Name, parentResourceType.FullName));
                            }

                            // Provide a better error message for collection of wrong types
                            if (collection)
                            {
                                throw new InvalidOperationException(Strings.ReflectionProvider_CollectionOfUnsupportedTypeProperty(property.Name, parentResourceType.FullName, resourcePropertyType));
                            }

                            if (CommonUtil.IsUnsupportedType(resourcePropertyType))
                            {
                                throw new InvalidOperationException(Strings.BadProvider_UnsupportedPropertyType(property.Name, parentResourceType.FullName));
                            }

                            throw new InvalidOperationException(Strings.ReflectionProvider_InvalidProperty(property.Name, parentResourceType.FullName));
                        }

                        // Navigation property on a complex type is not supported
                        throw new InvalidOperationException(Strings.ReflectionProvider_ComplexTypeWithNavigationProperty(property.Name, parentResourceType.FullName));
                    }

                    if (resourceType.ResourceTypeKind == ResourceTypeKind.EntityType)
                    {
                        ResourceSet container = InternalGetContainerForResourceType(resourcePropertyType, metadataCacheItem.EntitySets.Values);
                        if (container == null)
                        {
                            throw new InvalidOperationException(Strings.ReflectionProvider_EntityPropertyWithNoEntitySet(parentResourceType.FullName, property.Name));
                        }
                    }

                    if (kind == ResourcePropertyKind.Collection)
                    {
                        // Collection properties need the collection type (representing the IEnumerable<> part).
                        resourceType = ResourceType.GetCollectionResourceType(resourceType);
                    }

                    if (etagPropertyNames.Remove(property.Name))
                    {
                        kind |= ResourcePropertyKind.ETag;
                    }

                    ResourceProperty resourceProperty = new ResourceProperty(property.Name, kind, resourceType);
                    MimeTypeAttribute attribute = BaseServiceProvider.GetMimeTypeAttribute(property);
                    if (attribute != null)
                    {
                        resourceProperty.MimeType = attribute.MimeType;
                    }

                    parentResourceType.AddProperty(resourceProperty);
                }
                else
                {
                    throw new InvalidOperationException(Strings.ReflectionProvider_InvalidProperty(property.Name, parentResourceType.FullName));
                }
            }

            if (parentResourceType.ResourceTypeKind == ResourceTypeKind.EntityType &&
                (parentResourceType.KeyProperties == null || parentResourceType.KeyProperties.Count == 0))
            {
                throw new InvalidOperationException(Strings.ReflectionProvider_KeyPropertiesCannotBeIgnored(parentResourceType.FullName));
            }

            if (etagPropertyNames.Count != 0)
            {
                throw new InvalidOperationException(Strings.ReflectionProvider_ETagPropertyNameNotValid(etagPropertyNames.ElementAt(0), parentResourceType.FullName));
            }
        }