layers: Validate updating mutable type is allowed
diff --git a/layers/descriptor_sets.cpp b/layers/descriptor_sets.cpp
index bcfed5d..29cbf59 100644
--- a/layers/descriptor_sets.cpp
+++ b/layers/descriptor_sets.cpp
@@ -80,6 +80,18 @@
         sorted_bindings.emplace(p_create_info->pBindings + i, flags);
     }
 
+    const auto *mutable_descriptor_type_create_info = LvlFindInChain<VkMutableDescriptorTypeCreateInfoVALVE>(p_create_info->pNext);
+    if (mutable_descriptor_type_create_info) {
+        mutable_types_.resize(mutable_descriptor_type_create_info->mutableDescriptorTypeListCount);
+        for (uint32_t i = 0; i < mutable_descriptor_type_create_info->mutableDescriptorTypeListCount; ++i) {
+            const auto &list = mutable_descriptor_type_create_info->pMutableDescriptorTypeLists[i];
+            mutable_types_[i].reserve(list.descriptorTypeCount);
+            for (uint32_t j = 0; j < list.descriptorTypeCount; ++j) {
+                mutable_types_[i].push_back(list.pDescriptorTypes[j]);
+            }
+        }
+    }
+
     // Store the create info in the sorted order from above
     uint32_t index = 0;
     binding_count_ = static_cast<uint32_t>(sorted_bindings.size());
@@ -206,6 +218,22 @@
     return nullptr;
 }
 
+bool cvdescriptorset::DescriptorSetLayoutDef::IsTypeMutable(const VkDescriptorType type, uint32_t binding) const {
+    if (binding < mutable_types_.size()) {
+        if (mutable_types_[binding].size() > 0) {
+            for (const auto mutable_type : mutable_types_[binding]) {
+                if (type == mutable_type) {
+                    return true;
+                }
+            }
+            return false;
+        }
+    }
+    // If mutableDescriptorTypeListCount is zero or if VkMutableDescriptorTypeCreateInfoVALVE structure is not included in the pNext
+    // chain, the VkMutableDescriptorTypeListVALVE for each element is considered to be zero or NULL for each member.
+    return false;
+}
+
 // If our layout is compatible with rh_ds_layout, return true.
 bool cvdescriptorset::DescriptorSetLayout::IsCompatible(DescriptorSetLayout const *rh_ds_layout) const {
     bool compatible = (this == rh_ds_layout) || (GetLayoutDef() == rh_ds_layout->GetLayoutDef());
@@ -3436,6 +3464,19 @@
         *error_msg = error_str.str();
         return false;
     }
+    const auto orig_binding = DescriptorSetLayout::ConstBindingIterator(dest_set->GetLayout().get(), update->dstBinding);
+    if (!orig_binding.AtEnd() && orig_binding.GetType() == VK_DESCRIPTOR_TYPE_MUTABLE_VALVE) {
+        // Check if the new descriptor descriptor type is in the list of allowed mutable types for this binding
+        if (!orig_binding.Layout()->IsTypeMutable(update->descriptorType, update->dstBinding)) {
+            *error_code = "VUID-VkWriteDescriptorSet-dstSet-04611";
+            std::stringstream error_str;
+            error_str << "Write update type is " << string_VkDescriptorType(update->descriptorType)
+                      << ", but descriptor set layout binding was created with type VK_DESCRIPTOR_TYPE_MUTABLE_VALVE and used type "
+                         "is not in VkMutableDescriptorTypeListVALVE::pDescriptorTypes for this binding.";
+            *error_msg = error_str.str();
+            return false;
+        }
+    }
     // All checks passed, update is clean
     return true;
 }
diff --git a/layers/descriptor_sets.h b/layers/descriptor_sets.h
index 5ac768d..5aa1b03 100644
--- a/layers/descriptor_sets.h
+++ b/layers/descriptor_sets.h
@@ -175,6 +175,7 @@
     }
     VkSampler const *GetImmutableSamplerPtrFromBinding(const uint32_t) const;
     VkSampler const *GetImmutableSamplerPtrFromIndex(const uint32_t) const;
+    bool IsTypeMutable(const VkDescriptorType type, uint32_t binding) const;
     // For a particular binding, get the global index range
     //  This call should be guarded by a call to "HasBinding(binding)" to verify that the given binding exists
     const IndexRange &GetGlobalIndexRangeFromBinding(const uint32_t) const;
@@ -196,6 +197,8 @@
     VkDescriptorSetLayoutCreateFlags flags_;
     std::vector<safe_VkDescriptorSetLayoutBinding> bindings_;
     std::vector<VkDescriptorBindingFlags> binding_flags_;
+    // List of mutable types for each binding: [binding][mutable type]
+    std::vector<std::vector<VkDescriptorType>> mutable_types_;
 
     // Convenience data structures for rapid lookup of various descriptor set layout properties
     std::set<uint32_t> non_empty_bindings_;  // Containing non-emtpy bindings in numerical order
@@ -272,6 +275,7 @@
     VkSampler const *GetImmutableSamplerPtrFromIndex(const uint32_t index) const {
         return layout_id_->GetImmutableSamplerPtrFromIndex(index);
     }
+    bool IsTypeMutable(const VkDescriptorType type, uint32_t binding) const { return layout_id_->IsTypeMutable(type, binding); }
     // For a particular binding, get the global index range
     //  This call should be guarded by a call to "HasBinding(binding)" to verify that the given binding exists
     const IndexRange &GetGlobalIndexRangeFromBinding(const uint32_t binding) const {