diff --git a/config/Sources.cmake b/config/Sources.cmake
index 54bb3485ed975669668d987787975f019aa6358b..a8b7eb7a462117c6a71fc3b3facff48ede33f02b 100644
--- a/config/Sources.cmake
+++ b/config/Sources.cmake
@@ -35,8 +35,6 @@ set(vkcv_sources
 		${vkcv_include}/vkcv/Swapchain.hpp
 		${vkcv_source}/vkcv/Swapchain.cpp
 		
-		${vkcv_include}/vkcv/ShaderStage.hpp
-		
 		${vkcv_include}/vkcv/ShaderProgram.hpp
 		${vkcv_source}/vkcv/ShaderProgram.cpp
 
diff --git a/include/vkcv/Core.hpp b/include/vkcv/Core.hpp
index cbbe1e908cdb74891ab9bfe4416c03e487e76b26..d865b06151ba7f95048c67caf6baaf490af516f6 100644
--- a/include/vkcv/Core.hpp
+++ b/include/vkcv/Core.hpp
@@ -227,12 +227,13 @@ namespace vkcv
         [[nodiscard]]
         const uint32_t getImageHeight(ImageHandle imageHandle);
 
-        /** TODO:
-         *   @param setDescriptions
-         *   @return
+        /**
+         * Creates a descriptor set from the given bindings
+         * @param bindings an unordered map of descriptor bindings
+         * @return descriptor set handle
          */
         [[nodiscard]]
-        DescriptorSetHandle createDescriptorSet(const std::vector<DescriptorBinding> &bindings);
+        DescriptorSetHandle createDescriptorSet(const std::unordered_map<uint32_t, DescriptorBinding> &bindings);
 		void writeDescriptorSet(DescriptorSetHandle handle, const DescriptorWrites& writes);
 
 		DescriptorSet getDescriptorSet(const DescriptorSetHandle handle) const;
diff --git a/include/vkcv/DescriptorConfig.hpp b/include/vkcv/DescriptorConfig.hpp
index 78e111f40144a825bb790149f02a91039eb517b9..f34c6707baf6df10d3601015e05a894571d60e37 100644
--- a/include/vkcv/DescriptorConfig.hpp
+++ b/include/vkcv/DescriptorConfig.hpp
@@ -3,7 +3,6 @@
 #include <vulkan/vulkan.hpp>
 
 #include "vkcv/Handles.hpp"
-#include "vkcv/ShaderStage.hpp"
 
 namespace vkcv
 {
@@ -35,15 +34,15 @@ namespace vkcv
     struct DescriptorBinding
     {
         DescriptorBinding(
-            uint32_t bindingID,
-            DescriptorType descriptorType,
-            uint32_t descriptorCount,
-            ShaderStages shaderStages
+            uint32_t             bindingID,
+            DescriptorType       descriptorType,
+            uint32_t             descriptorCount,
+            vk::ShaderStageFlags shaderStages
         ) noexcept;
         
-        uint32_t bindingID;
-        DescriptorType descriptorType;
-        uint32_t descriptorCount;
-        ShaderStages shaderStages;
+        uint32_t                bindingID;
+        DescriptorType          descriptorType;
+        uint32_t                descriptorCount;
+        vk::ShaderStageFlags    shaderStages;
     };
 }
diff --git a/include/vkcv/ShaderProgram.hpp b/include/vkcv/ShaderProgram.hpp
index c7d67b19148b3c9ec19ce1b539f9661797d1b38f..e4d995b3ab1f87ac94ca1738f932dba39f4cd5c9 100644
--- a/include/vkcv/ShaderProgram.hpp
+++ b/include/vkcv/ShaderProgram.hpp
@@ -14,14 +14,13 @@
 #include <spirv_cross.hpp>
 #include "VertexLayout.hpp"
 #include "DescriptorConfig.hpp"
-#include "ShaderStage.hpp"
 
 namespace vkcv {
 
     struct Shader
     {
         std::vector<char> shaderCode;
-        ShaderStage shaderStage;
+        vk::ShaderStageFlags shaderStage;
     };
 
 	class ShaderProgram
@@ -37,21 +36,21 @@ namespace vkcv {
         * @param[in] flag that signals the respective shaderStage (e.g. VK_SHADER_STAGE_VERTEX_BIT)
         * @param[in] relative path to the shader code (e.g. "../../../../../shaders/vert.spv")
         */
-        bool addShader(ShaderStage shaderStage, const std::filesystem::path &shaderPath);
+        bool addShader(vk::ShaderStageFlagBits shaderStage, const std::filesystem::path &shaderPath);
 
         /**
         * Returns the shader program's shader of the specified shader.
         * Needed for the transfer to the pipeline.
         * @return Shader object consisting of buffer with shader code and shader stage enum
         */
-        const Shader &getShader(ShaderStage shaderStage) const;
+        const Shader &getShader(vk::ShaderStageFlagBits shaderStage) const;
 
-        bool existsShader(ShaderStage shaderStage) const;
+        bool existsShader(vk::ShaderStageFlagBits shaderStage) const;
 
         const std::vector<VertexAttachment> &getVertexAttachments() const;
 		size_t getPushConstantSize() const;
 
-        const std::vector<std::vector<DescriptorBinding>>& getReflectedDescriptors() const;
+        const std::unordered_map<uint32_t, std::unordered_map<uint32_t, DescriptorBinding>>& getReflectedDescriptors() const;
 
 	private:
 	    /**
@@ -59,13 +58,21 @@ namespace vkcv {
 	     * Fills vertex input attachments and descriptor sets (if present).
 	     * @param shaderStage the stage to reflect data from
 	     */
-        void reflectShader(ShaderStage shaderStage);
+        void reflectShader(vk::ShaderStageFlagBits shaderStage);
 
-        std::unordered_map<ShaderStage, Shader> m_Shaders;
+        std::unordered_map<vk::ShaderStageFlagBits, Shader> m_Shaders;
 
         // contains all vertex input attachments used in the vertex buffer
         std::vector<VertexAttachment> m_VertexAttachments;
-        std::vector<std::vector<DescriptorBinding>> m_DescriptorSets;
+
+        /**
+         * Map of map structure
+         * First Key: Set ID, return an unordered map to the corresponding set's bindings
+         * Second Key: Binding ID, returns the actual descriptor binding description
+         * Value: descriptor binding description
+         */
+        std::unordered_map<uint32_t, std::unordered_map<uint32_t, DescriptorBinding>> m_DescriptorSets;
+
 		size_t m_pushConstantSize = 0;
 	};
 }
diff --git a/include/vkcv/ShaderStage.hpp b/include/vkcv/ShaderStage.hpp
deleted file mode 100644
index d671b87b55ac7a5a8926e479c77fa991dd90c665..0000000000000000000000000000000000000000
--- a/include/vkcv/ShaderStage.hpp
+++ /dev/null
@@ -1,38 +0,0 @@
-#pragma once
-
-#include <vulkan/vulkan.hpp>
-
-namespace vkcv {
-	
-	enum class ShaderStage : VkShaderStageFlags {
-		VERTEX = static_cast<VkShaderStageFlags>(vk::ShaderStageFlagBits::eVertex),
-		TESS_CONTROL = static_cast<VkShaderStageFlags>(vk::ShaderStageFlagBits::eTessellationControl),
-		TESS_EVAL = static_cast<VkShaderStageFlags>(vk::ShaderStageFlagBits::eTessellationEvaluation),
-		GEOMETRY = static_cast<VkShaderStageFlags>(vk::ShaderStageFlagBits::eGeometry),
-		FRAGMENT = static_cast<VkShaderStageFlags>(vk::ShaderStageFlagBits::eFragment),
-		COMPUTE = static_cast<VkShaderStageFlags>(vk::ShaderStageFlagBits::eCompute)
-	};
-	
-	using ShaderStages = vk::Flags<ShaderStage>;
-	
-	constexpr vk::ShaderStageFlags getShaderStageFlags(ShaderStages shaderStages) noexcept {
-		return vk::ShaderStageFlags(static_cast<VkShaderStageFlags>(shaderStages));
-	}
-	
-	constexpr ShaderStages operator|(ShaderStage stage0, ShaderStage stage1) noexcept {
-		return ShaderStages(stage0) | stage1;
-	}
-	
-	constexpr ShaderStages operator&(ShaderStage stage0, ShaderStage stage1) noexcept {
-		return ShaderStages(stage0) & stage1;
-	}
-	
-	constexpr ShaderStages operator^(ShaderStage stage0, ShaderStage stage1) noexcept {
-		return ShaderStages(stage0) ^ stage1;
-	}
-	
-	constexpr ShaderStages operator~(ShaderStage stage) noexcept {
-		return ~(ShaderStages(stage));
-	}
-	
-}
diff --git a/modules/material/include/vkcv/material/PBRMaterial.hpp b/modules/material/include/vkcv/material/PBRMaterial.hpp
index 09a5214b0e748a09ef8caefe5bf2b1a69ecbd8e1..48d456d67b7c327fb860eb37456f0b40ee40ec0e 100644
--- a/modules/material/include/vkcv/material/PBRMaterial.hpp
+++ b/modules/material/include/vkcv/material/PBRMaterial.hpp
@@ -78,7 +78,7 @@ namespace vkcv::material
         * 8 - emissive texture
         * 9 - emissive sampler
         */
-        static std::vector<DescriptorBinding> getDescriptorBindings() noexcept;
+        static std::unordered_map<uint32_t, DescriptorBinding> getDescriptorBindings() noexcept;
 
         static PBRMaterial create(
             vkcv::Core* core,
diff --git a/modules/material/src/vkcv/material/PBRMaterial.cpp b/modules/material/src/vkcv/material/PBRMaterial.cpp
index d27e755c06a39e369d22efc997a0b411d067c132..9d86f4f18e8df8c9b5fd8ecb4f88e7de1b59ff10 100644
--- a/modules/material/src/vkcv/material/PBRMaterial.cpp
+++ b/modules/material/src/vkcv/material/PBRMaterial.cpp
@@ -41,21 +41,21 @@ namespace vkcv::material
     {
     }
 
-    std::vector<DescriptorBinding> PBRMaterial::getDescriptorBindings() noexcept
+    std::unordered_map<uint32_t, DescriptorBinding> PBRMaterial::getDescriptorBindings() noexcept
     {
-		static std::vector<DescriptorBinding> bindings;
-		
+		static std::unordered_map<uint32_t, DescriptorBinding> bindings;
+
 		if (bindings.empty()) {
-			bindings.emplace_back(0, DescriptorType::IMAGE_SAMPLED, 1, ShaderStage::FRAGMENT);
-			bindings.emplace_back(1, DescriptorType::SAMPLER, 1, ShaderStage::FRAGMENT);
-			bindings.emplace_back(2, DescriptorType::IMAGE_SAMPLED, 1, ShaderStage::FRAGMENT);
-			bindings.emplace_back(3, DescriptorType::SAMPLER, 1, ShaderStage::FRAGMENT);
-			bindings.emplace_back(4, DescriptorType::IMAGE_SAMPLED, 1, ShaderStage::FRAGMENT);
-			bindings.emplace_back(5, DescriptorType::SAMPLER, 1, ShaderStage::FRAGMENT);
-			bindings.emplace_back(6, DescriptorType::IMAGE_SAMPLED, 1, ShaderStage::FRAGMENT);
-			bindings.emplace_back(7, DescriptorType::SAMPLER, 1, ShaderStage::FRAGMENT);
-			bindings.emplace_back(8, DescriptorType::IMAGE_SAMPLED, 1, ShaderStage::FRAGMENT);
-			bindings.emplace_back(9, DescriptorType::SAMPLER, 1, ShaderStage::FRAGMENT);
+			bindings.insert(std::make_pair(0, DescriptorBinding(0, DescriptorType::IMAGE_SAMPLED, 1, vk::ShaderStageFlagBits::eFragment)));
+			bindings.insert(std::make_pair(1, DescriptorBinding(1, DescriptorType::SAMPLER, 1, vk::ShaderStageFlagBits::eFragment)));
+            bindings.insert(std::make_pair(2, DescriptorBinding(2, DescriptorType::IMAGE_SAMPLED, 1, vk::ShaderStageFlagBits::eFragment)));
+            bindings.insert(std::make_pair(3, DescriptorBinding(3, DescriptorType::SAMPLER, 1, vk::ShaderStageFlagBits::eFragment)));
+            bindings.insert(std::make_pair(4, DescriptorBinding(4, DescriptorType::IMAGE_SAMPLED, 1, vk::ShaderStageFlagBits::eFragment)));
+            bindings.insert(std::make_pair(5, DescriptorBinding(5, DescriptorType::SAMPLER, 1, vk::ShaderStageFlagBits::eFragment)));
+            bindings.insert(std::make_pair(6, DescriptorBinding(6, DescriptorType::IMAGE_SAMPLED, 1, vk::ShaderStageFlagBits::eFragment)));
+            bindings.insert(std::make_pair(7, DescriptorBinding(7, DescriptorType::SAMPLER, 1, vk::ShaderStageFlagBits::eFragment)));
+            bindings.insert(std::make_pair(8, DescriptorBinding(8, DescriptorType::IMAGE_SAMPLED, 1, vk::ShaderStageFlagBits::eFragment)));
+            bindings.insert(std::make_pair(9, DescriptorBinding(9, DescriptorType::SAMPLER, 1, vk::ShaderStageFlagBits::eFragment)));
 		}
     	
         return bindings;
diff --git a/modules/shader_compiler/include/vkcv/shader/Compiler.hpp b/modules/shader_compiler/include/vkcv/shader/Compiler.hpp
index d7b7af7178531aea358cecbc8b86a29527173014..118023fcb4244c0c91d8c9eca450c806d758cc5c 100644
--- a/modules/shader_compiler/include/vkcv/shader/Compiler.hpp
+++ b/modules/shader_compiler/include/vkcv/shader/Compiler.hpp
@@ -4,12 +4,12 @@
 
 namespace vkcv::shader {
 	
-	typedef typename event_function<ShaderStage, const std::filesystem::path&>::type ShaderCompiledFunction;
+	typedef typename event_function<vk::ShaderStageFlagBits, const std::filesystem::path&>::type ShaderCompiledFunction;
 	
 	class Compiler {
 	private:
 	public:
-		virtual void compile(ShaderStage shaderStage, const std::filesystem::path& shaderPath,
+		virtual void compile(vk::ShaderStageFlagBits shaderStage, const std::filesystem::path& shaderPath,
 							 const ShaderCompiledFunction& compiled, bool update = false) = 0;
 		
 	};
diff --git a/modules/shader_compiler/include/vkcv/shader/GLSLCompiler.hpp b/modules/shader_compiler/include/vkcv/shader/GLSLCompiler.hpp
index 7105d93a0c3e153bf3abe1d624d0c13c6f09ac6d..bd31a80a6d013374957288378143798f3da05b1b 100644
--- a/modules/shader_compiler/include/vkcv/shader/GLSLCompiler.hpp
+++ b/modules/shader_compiler/include/vkcv/shader/GLSLCompiler.hpp
@@ -1,8 +1,7 @@
 #pragma once
 
 #include <filesystem>
-
-#include <vkcv/ShaderStage.hpp>
+#include <vulkan/vulkan.hpp>
 #include "Compiler.hpp"
 
 namespace vkcv::shader {
@@ -20,7 +19,7 @@ namespace vkcv::shader {
 		GLSLCompiler& operator=(const GLSLCompiler& other);
 		GLSLCompiler& operator=(GLSLCompiler&& other) = default;
 		
-		void compile(ShaderStage shaderStage, const std::filesystem::path& shaderPath,
+		void compile(vk::ShaderStageFlagBits shaderStage, const std::filesystem::path& shaderPath,
 					 const ShaderCompiledFunction& compiled, bool update = false);
 		
 	};
diff --git a/modules/shader_compiler/src/vkcv/shader/GLSLCompiler.cpp b/modules/shader_compiler/src/vkcv/shader/GLSLCompiler.cpp
index ec358188b8e871da6f4d62ffd397f32bfb795ee2..8d5246b5f6ee058f118d90e272ec5eb05e54cb10 100644
--- a/modules/shader_compiler/src/vkcv/shader/GLSLCompiler.cpp
+++ b/modules/shader_compiler/src/vkcv/shader/GLSLCompiler.cpp
@@ -36,19 +36,19 @@ namespace vkcv::shader {
 		return *this;
 	}
 	
-	constexpr EShLanguage findShaderLanguage(ShaderStage shaderStage) {
+	constexpr EShLanguage findShaderLanguage(vk::ShaderStageFlagBits shaderStage) {
 		switch (shaderStage) {
-			case ShaderStage::VERTEX:
+			case vk::ShaderStageFlagBits::eVertex:
 				return EShLangVertex;
-			case ShaderStage::TESS_CONTROL:
+			case vk::ShaderStageFlagBits::eTessellationControl:
 				return EShLangTessControl;
-			case ShaderStage::TESS_EVAL:
+			case vk::ShaderStageFlagBits::eTessellationEvaluation:
 				return EShLangTessEvaluation;
-			case ShaderStage::GEOMETRY:
+			case vk::ShaderStageFlagBits::eGeometry:
 				return EShLangGeometry;
-			case ShaderStage::FRAGMENT:
+			case vk::ShaderStageFlagBits::eFragment:
 				return EShLangFragment;
-			case ShaderStage::COMPUTE:
+			case vk::ShaderStageFlagBits::eCompute:
 				return EShLangCompute;
 			default:
 				return EShLangCount;
@@ -197,7 +197,7 @@ namespace vkcv::shader {
 		return true;
 	}
 	
-	void GLSLCompiler::compile(ShaderStage shaderStage, const std::filesystem::path &shaderPath,
+	void GLSLCompiler::compile(vk::ShaderStageFlagBits shaderStage, const std::filesystem::path &shaderPath,
 							   const ShaderCompiledFunction& compiled, bool update) {
 		const EShLanguage language = findShaderLanguage(shaderStage);
 		
diff --git a/projects/bloom/src/BloomAndFlares.cpp b/projects/bloom/src/BloomAndFlares.cpp
index 6f26db9de0f2c8334b6dd7e5dd6cf4b6f48baedc..c6e27f3e703cd7b2836249ee0975f42e1085eb04 100644
--- a/projects/bloom/src/BloomAndFlares.cpp
+++ b/projects/bloom/src/BloomAndFlares.cpp
@@ -22,57 +22,57 @@ BloomAndFlares::BloomAndFlares(
 
     // DOWNSAMPLE
     vkcv::ShaderProgram dsProg;
-    compiler.compile(vkcv::ShaderStage::COMPUTE,
+    compiler.compile(vk::ShaderStageFlagBits::eCompute,
                      "resources/shaders/downsample.comp",
-                     [&](vkcv::ShaderStage shaderStage, const std::filesystem::path& path)
+                     [&](vk::ShaderStageFlagBits shaderStage, const std::filesystem::path& path)
                      {
                          dsProg.addShader(shaderStage, path);
                      });
     for(uint32_t mipLevel = 0; mipLevel < m_Blur.getMipCount(); mipLevel++)
     {
 		m_DownsampleDescSets.push_back(
-                p_Core->createDescriptorSet(dsProg.getReflectedDescriptors()[0]));
+                p_Core->createDescriptorSet(dsProg.getReflectedDescriptors().at(0)));
     }
     m_DownsamplePipe = p_Core->createComputePipeline(
             dsProg, { p_Core->getDescriptorSet(m_DownsampleDescSets[0]).layout });
 
     // UPSAMPLE
     vkcv::ShaderProgram usProg;
-    compiler.compile(vkcv::ShaderStage::COMPUTE,
+    compiler.compile(vk::ShaderStageFlagBits::eCompute,
                      "resources/shaders/upsample.comp",
-                     [&](vkcv::ShaderStage shaderStage, const std::filesystem::path& path)
+                     [&](vk::ShaderStageFlagBits shaderStage, const std::filesystem::path& path)
                      {
                          usProg.addShader(shaderStage, path);
                      });
     for(uint32_t mipLevel = 0; mipLevel < m_Blur.getMipCount(); mipLevel++)
     {
         m_UpsampleDescSets.push_back(
-                p_Core->createDescriptorSet(usProg.getReflectedDescriptors()[0]));
+                p_Core->createDescriptorSet(usProg.getReflectedDescriptors().at(0)));
     }
     m_UpsamplePipe = p_Core->createComputePipeline(
             usProg, { p_Core->getDescriptorSet(m_UpsampleDescSets[0]).layout });
 
     // LENS FEATURES
     vkcv::ShaderProgram lensProg;
-    compiler.compile(vkcv::ShaderStage::COMPUTE,
+    compiler.compile(vk::ShaderStageFlagBits::eCompute,
                      "resources/shaders/lensFlares.comp",
-                     [&](vkcv::ShaderStage shaderStage, const std::filesystem::path& path)
+                     [&](vk::ShaderStageFlagBits shaderStage, const std::filesystem::path& path)
                      {
                          lensProg.addShader(shaderStage, path);
                      });
-    m_LensFlareDescSet = p_Core->createDescriptorSet(lensProg.getReflectedDescriptors()[0]);
+    m_LensFlareDescSet = p_Core->createDescriptorSet(lensProg.getReflectedDescriptors().at(0));
     m_LensFlarePipe = p_Core->createComputePipeline(
             lensProg, { p_Core->getDescriptorSet(m_LensFlareDescSet).layout });
 
     // COMPOSITE
     vkcv::ShaderProgram compProg;
-    compiler.compile(vkcv::ShaderStage::COMPUTE,
+    compiler.compile(vk::ShaderStageFlagBits::eCompute,
                      "resources/shaders/composite.comp",
-                     [&](vkcv::ShaderStage shaderStage, const std::filesystem::path& path)
+                     [&](vk::ShaderStageFlagBits shaderStage, const std::filesystem::path& path)
                      {
                          compProg.addShader(shaderStage, path);
                      });
-    m_CompositeDescSet = p_Core->createDescriptorSet(compProg.getReflectedDescriptors()[0]);
+    m_CompositeDescSet = p_Core->createDescriptorSet(compProg.getReflectedDescriptors().at(0));
     m_CompositePipe = p_Core->createComputePipeline(
             compProg, { p_Core->getDescriptorSet(m_CompositeDescSet).layout });
 }
diff --git a/projects/bloom/src/main.cpp b/projects/bloom/src/main.cpp
index 7a17a51f1c7d638575c0b5aafcdca49b589533ef..96085db747b1d2bb837d9803eb854a191f34f574 100644
--- a/projects/bloom/src/main.cpp
+++ b/projects/bloom/src/main.cpp
@@ -121,12 +121,12 @@ int main(int argc, const char** argv) {
 	vkcv::shader::GLSLCompiler compiler;
 
 	vkcv::ShaderProgram forwardProgram;
-	compiler.compile(vkcv::ShaderStage::VERTEX, std::filesystem::path("resources/shaders/shader.vert"), 
-		[&](vkcv::ShaderStage shaderStage, const std::filesystem::path& path) {
+	compiler.compile(vk::ShaderStageFlagBits::eVertex, std::filesystem::path("resources/shaders/shader.vert"),
+		[&](vk::ShaderStageFlagBits shaderStage, const std::filesystem::path& path) {
 		forwardProgram.addShader(shaderStage, path);
 	});
-	compiler.compile(vkcv::ShaderStage::FRAGMENT, std::filesystem::path("resources/shaders/shader.frag"),
-		[&](vkcv::ShaderStage shaderStage, const std::filesystem::path& path) {
+	compiler.compile(vk::ShaderStageFlagBits::eFragment, std::filesystem::path("resources/shaders/shader.frag"),
+		[&](vk::ShaderStageFlagBits shaderStage, const std::filesystem::path& path) {
 		forwardProgram.addShader(shaderStage, path);
 	});
 
@@ -159,7 +159,7 @@ int main(int argc, const char** argv) {
 	vkcv::Buffer lightBuffer = core.createBuffer<LightInfo>(vkcv::BufferType::UNIFORM, sizeof(glm::vec3));
 
 	vkcv::DescriptorSetHandle forwardShadingDescriptorSet = 
-		core.createDescriptorSet({ forwardProgram.getReflectedDescriptors()[0] });
+		core.createDescriptorSet(forwardProgram.getReflectedDescriptors().at(0));
 
 	vkcv::DescriptorWrites forwardDescriptorWrites;
 	forwardDescriptorWrites.uniformBufferWrites = { vkcv::UniformBufferDescriptorWrite(0, lightBuffer.getHandle()) };
@@ -178,7 +178,7 @@ int main(int argc, const char** argv) {
 	std::vector<vkcv::DescriptorSetHandle> perMeshDescriptorSets;
 	std::vector<vkcv::Image> sceneImages;
 	for (const auto& vertexGroup : scene.vertexGroups) {
-		perMeshDescriptorSets.push_back(core.createDescriptorSet(forwardProgram.getReflectedDescriptors()[1]));
+		perMeshDescriptorSets.push_back(core.createDescriptorSet(forwardProgram.getReflectedDescriptors().at(1)));
 
 		const auto& material = scene.materials[vertexGroup.materialIndex];
 
@@ -227,12 +227,12 @@ int main(int argc, const char** argv) {
 	const vkcv::ImageHandle swapchainInput = vkcv::ImageHandle::createSwapchainImageHandle();
 
 	vkcv::ShaderProgram shadowShader;
-	compiler.compile(vkcv::ShaderStage::VERTEX, "resources/shaders/shadow.vert",
-		[&](vkcv::ShaderStage shaderStage, const std::filesystem::path& path) {
+	compiler.compile(vk::ShaderStageFlagBits::eVertex, "resources/shaders/shadow.vert",
+		[&](vk::ShaderStageFlagBits shaderStage, const std::filesystem::path& path) {
 		shadowShader.addShader(shaderStage, path);
 	});
-	compiler.compile(vkcv::ShaderStage::FRAGMENT, "resources/shaders/shadow.frag",
-		[&](vkcv::ShaderStage shaderStage, const std::filesystem::path& path) {
+	compiler.compile(vk::ShaderStageFlagBits::eFragment, "resources/shaders/shadow.frag",
+		[&](vk::ShaderStageFlagBits shaderStage, const std::filesystem::path& path) {
 		shadowShader.addShader(shaderStage, path);
 	});
 
@@ -257,11 +257,11 @@ int main(int argc, const char** argv) {
 
 	// gamma correction compute shader
 	vkcv::ShaderProgram gammaCorrectionProgram;
-	compiler.compile(vkcv::ShaderStage::COMPUTE, "resources/shaders/gammaCorrection.comp",
-		[&](vkcv::ShaderStage shaderStage, const std::filesystem::path& path) {
+	compiler.compile(vk::ShaderStageFlagBits::eCompute, "resources/shaders/gammaCorrection.comp",
+		[&](vk::ShaderStageFlagBits shaderStage, const std::filesystem::path& path) {
 		gammaCorrectionProgram.addShader(shaderStage, path);
 	});
-	vkcv::DescriptorSetHandle gammaCorrectionDescriptorSet = core.createDescriptorSet(gammaCorrectionProgram.getReflectedDescriptors()[0]);
+	vkcv::DescriptorSetHandle gammaCorrectionDescriptorSet = core.createDescriptorSet(gammaCorrectionProgram.getReflectedDescriptors().at(0));
 	vkcv::PipelineHandle gammaCorrectionPipeline = core.createComputePipeline(gammaCorrectionProgram,
 		{ core.getDescriptorSet(gammaCorrectionDescriptorSet).layout });
 
diff --git a/projects/first_mesh/src/main.cpp b/projects/first_mesh/src/main.cpp
index e7546fc3a143b3638cceb36869c519336ebec751..c941e94e5bf4414635ec58a1d161c98844bf46a5 100644
--- a/projects/first_mesh/src/main.cpp
+++ b/projects/first_mesh/src/main.cpp
@@ -79,8 +79,8 @@ int main(int argc, const char** argv) {
 	}
 
 	vkcv::ShaderProgram firstMeshProgram{};
-    firstMeshProgram.addShader(vkcv::ShaderStage::VERTEX, std::filesystem::path("resources/shaders/vert.spv"));
-    firstMeshProgram.addShader(vkcv::ShaderStage::FRAGMENT, std::filesystem::path("resources/shaders/frag.spv"));
+    firstMeshProgram.addShader(vk::ShaderStageFlagBits::eVertex, std::filesystem::path("resources/shaders/vert.spv"));
+    firstMeshProgram.addShader(vk::ShaderStageFlagBits::eFragment, std::filesystem::path("resources/shaders/frag.spv"));
 	
 	auto& attributes = mesh.vertexGroups[0].vertexBuffer.attributes;
 
@@ -98,8 +98,8 @@ int main(int argc, const char** argv) {
 	const vkcv::VertexLayout firstMeshLayout (bindings);
 
 	uint32_t setID = 0;
-	std::vector<vkcv::DescriptorBinding> descriptorBindings = { firstMeshProgram.getReflectedDescriptors()[setID] };
-	vkcv::DescriptorSetHandle descriptorSet = core.createDescriptorSet(descriptorBindings);
+
+	vkcv::DescriptorSetHandle descriptorSet = core.createDescriptorSet(firstMeshProgram.getReflectedDescriptors().at(setID));
 
 	const vkcv::PipelineConfig firstMeshPipelineConfig {
         firstMeshProgram,
diff --git a/projects/first_scene/src/main.cpp b/projects/first_scene/src/main.cpp
index 521818732f7a60eabe9f0c2c080c6d343a71b1d8..842018f6b623da0dfe5c634f018cf3f84bf9c437 100644
--- a/projects/first_scene/src/main.cpp
+++ b/projects/first_scene/src/main.cpp
@@ -128,8 +128,8 @@ int main(int argc, const char** argv) {
 	}
 
 	vkcv::ShaderProgram sceneShaderProgram{};
-	sceneShaderProgram.addShader(vkcv::ShaderStage::VERTEX, std::filesystem::path("resources/shaders/vert.spv"));
-	sceneShaderProgram.addShader(vkcv::ShaderStage::FRAGMENT, std::filesystem::path("resources/shaders/frag.spv"));
+	sceneShaderProgram.addShader(vk::ShaderStageFlagBits::eVertex, std::filesystem::path("resources/shaders/vert.spv"));
+	sceneShaderProgram.addShader(vk::ShaderStageFlagBits::eFragment, std::filesystem::path("resources/shaders/frag.spv"));
 
 	const std::vector<vkcv::VertexAttachment> vertexAttachments = sceneShaderProgram.getVertexAttachments();
 	std::vector<vkcv::VertexBinding> bindings;
@@ -141,8 +141,6 @@ int main(int argc, const char** argv) {
 
 	uint32_t setID = 0;
 
-	std::vector<vkcv::DescriptorBinding> descriptorBindings = { sceneShaderProgram.getReflectedDescriptors()[setID] };
-
 	vkcv::SamplerHandle sampler = core.createSampler(
 		vkcv::SamplerFilterType::LINEAR,
 		vkcv::SamplerFilterType::LINEAR,
@@ -153,7 +151,7 @@ int main(int argc, const char** argv) {
 	std::vector<vkcv::Image> sceneImages;
 	std::vector<vkcv::DescriptorSetHandle> descriptorSets;
 	for (const auto& vertexGroup : scene.vertexGroups) {
-		descriptorSets.push_back(core.createDescriptorSet(descriptorBindings));
+		descriptorSets.push_back(core.createDescriptorSet(sceneShaderProgram.getReflectedDescriptors().at(setID)));
 
 		const auto& material = scene.materials[vertexGroup.materialIndex];
 
diff --git a/projects/first_triangle/src/main.cpp b/projects/first_triangle/src/main.cpp
index 5bdd55a263f4d81d8f424c056d7d6c0b54ccb1ca..da3521718b4a8f215e15a863e6d7f60e66d39372 100644
--- a/projects/first_triangle/src/main.cpp
+++ b/projects/first_triangle/src/main.cpp
@@ -96,13 +96,13 @@ int main(int argc, const char** argv) {
 	vkcv::ShaderProgram triangleShaderProgram{};
 	vkcv::shader::GLSLCompiler compiler;
 	
-	compiler.compile(vkcv::ShaderStage::VERTEX, std::filesystem::path("shaders/shader.vert"),
-					 [&triangleShaderProgram](vkcv::ShaderStage shaderStage, const std::filesystem::path& path) {
+	compiler.compile(vk::ShaderStageFlagBits::eVertex, std::filesystem::path("shaders/shader.vert"),
+					 [&triangleShaderProgram](vk::ShaderStageFlagBits shaderStage, const std::filesystem::path& path) {
 		 triangleShaderProgram.addShader(shaderStage, path);
 	});
 	
-	compiler.compile(vkcv::ShaderStage::FRAGMENT, std::filesystem::path("shaders/shader.frag"),
-					 [&triangleShaderProgram](vkcv::ShaderStage shaderStage, const std::filesystem::path& path) {
+	compiler.compile(vk::ShaderStageFlagBits::eFragment, std::filesystem::path("shaders/shader.frag"),
+					 [&triangleShaderProgram](vk::ShaderStageFlagBits shaderStage, const std::filesystem::path& path) {
 		triangleShaderProgram.addShader(shaderStage, path);
 	});
 
@@ -126,10 +126,10 @@ int main(int argc, const char** argv) {
 
 	// Compute Pipeline
 	vkcv::ShaderProgram computeShaderProgram{};
-	computeShaderProgram.addShader(vkcv::ShaderStage::COMPUTE, std::filesystem::path("shaders/comp.spv"));
+	computeShaderProgram.addShader(vk::ShaderStageFlagBits::eCompute, std::filesystem::path("shaders/comp.spv"));
 
 	// take care, assuming shader has exactly one descriptor set
-	vkcv::DescriptorSetHandle computeDescriptorSet = core.createDescriptorSet(computeShaderProgram.getReflectedDescriptors()[0]);
+	vkcv::DescriptorSetHandle computeDescriptorSet = core.createDescriptorSet(computeShaderProgram.getReflectedDescriptors().at(0));
 
 	vkcv::PipelineHandle computePipeline = core.createComputePipeline(
 		computeShaderProgram, 
diff --git a/projects/particle_simulation/src/BloomAndFlares.cpp b/projects/particle_simulation/src/BloomAndFlares.cpp
index 23ace2bc35a2e421613718c62380f9161a408f70..8140583e3b0796ee9b73410fafa47b66fe315ce3 100644
--- a/projects/particle_simulation/src/BloomAndFlares.cpp
+++ b/projects/particle_simulation/src/BloomAndFlares.cpp
@@ -22,57 +22,57 @@ BloomAndFlares::BloomAndFlares(
 
     // DOWNSAMPLE
     vkcv::ShaderProgram dsProg;
-    compiler.compile(vkcv::ShaderStage::COMPUTE,
+    compiler.compile(vk::ShaderStageFlagBits::eCompute,
                      "shaders/bloom/downsample.comp",
-                     [&](vkcv::ShaderStage shaderStage, const std::filesystem::path& path)
+                     [&](vk::ShaderStageFlagBits shaderStage, const std::filesystem::path& path)
                      {
                          dsProg.addShader(shaderStage, path);
                      });
     for(uint32_t mipLevel = 0; mipLevel < m_Blur.getMipCount(); mipLevel++)
     {
 		m_DownsampleDescSets.push_back(
-                p_Core->createDescriptorSet(dsProg.getReflectedDescriptors()[0]));
+                p_Core->createDescriptorSet(dsProg.getReflectedDescriptors().at(0)));
     }
     m_DownsamplePipe = p_Core->createComputePipeline(
             dsProg, { p_Core->getDescriptorSet(m_DownsampleDescSets[0]).layout });
 
     // UPSAMPLE
     vkcv::ShaderProgram usProg;
-    compiler.compile(vkcv::ShaderStage::COMPUTE,
+    compiler.compile(vk::ShaderStageFlagBits::eCompute,
                      "shaders/bloom/upsample.comp",
-                     [&](vkcv::ShaderStage shaderStage, const std::filesystem::path& path)
+                     [&](vk::ShaderStageFlagBits shaderStage, const std::filesystem::path& path)
                      {
                          usProg.addShader(shaderStage, path);
                      });
     for(uint32_t mipLevel = 0; mipLevel < m_Blur.getMipCount(); mipLevel++)
     {
         m_UpsampleDescSets.push_back(
-                p_Core->createDescriptorSet(usProg.getReflectedDescriptors()[0]));
+                p_Core->createDescriptorSet(usProg.getReflectedDescriptors().at(0)));
     }
     m_UpsamplePipe = p_Core->createComputePipeline(
             usProg, { p_Core->getDescriptorSet(m_UpsampleDescSets[0]).layout });
 
     // LENS FEATURES
     vkcv::ShaderProgram lensProg;
-    compiler.compile(vkcv::ShaderStage::COMPUTE,
+    compiler.compile(vk::ShaderStageFlagBits::eCompute,
                      "shaders/bloom/lensFlares.comp",
-                     [&](vkcv::ShaderStage shaderStage, const std::filesystem::path& path)
+                     [&](vk::ShaderStageFlagBits shaderStage, const std::filesystem::path& path)
                      {
                          lensProg.addShader(shaderStage, path);
                      });
-    m_LensFlareDescSet = p_Core->createDescriptorSet(lensProg.getReflectedDescriptors()[0]);
+    m_LensFlareDescSet = p_Core->createDescriptorSet(lensProg.getReflectedDescriptors().at(0));
     m_LensFlarePipe = p_Core->createComputePipeline(
             lensProg, { p_Core->getDescriptorSet(m_LensFlareDescSet).layout });
 
     // COMPOSITE
     vkcv::ShaderProgram compProg;
-    compiler.compile(vkcv::ShaderStage::COMPUTE,
+    compiler.compile(vk::ShaderStageFlagBits::eCompute,
                      "shaders/bloom/composite.comp",
-                     [&](vkcv::ShaderStage shaderStage, const std::filesystem::path& path)
+                     [&](vk::ShaderStageFlagBits shaderStage, const std::filesystem::path& path)
                      {
                          compProg.addShader(shaderStage, path);
                      });
-    m_CompositeDescSet = p_Core->createDescriptorSet(compProg.getReflectedDescriptors()[0]);
+    m_CompositeDescSet = p_Core->createDescriptorSet(compProg.getReflectedDescriptors().at(0));
     m_CompositePipe = p_Core->createComputePipeline(
             compProg, { p_Core->getDescriptorSet(m_CompositeDescSet).layout });
 }
diff --git a/projects/particle_simulation/src/main.cpp b/projects/particle_simulation/src/main.cpp
index a22044f0d2588a43a5e7a0f6cba25d9c7460be9f..91672cdcddb18f18d07f8136d46440f6c432b029 100644
--- a/projects/particle_simulation/src/main.cpp
+++ b/projects/particle_simulation/src/main.cpp
@@ -63,11 +63,11 @@ int main(int argc, const char **argv) {
 
     vkcv::shader::GLSLCompiler compiler;
     vkcv::ShaderProgram computeShaderProgram{};
-    compiler.compile(vkcv::ShaderStage::COMPUTE, useSpace ? "shaders/shader_space.comp" : "shaders/shader_water.comp", [&](vkcv::ShaderStage shaderStage, const std::filesystem::path& path) {
+    compiler.compile(vk::ShaderStageFlagBits::eCompute, useSpace ? "shaders/shader_space.comp" : "shaders/shader_water.comp", [&](vk::ShaderStageFlagBits shaderStage, const std::filesystem::path& path) {
         computeShaderProgram.addShader(shaderStage, path);
     });
 
-    vkcv::DescriptorSetHandle computeDescriptorSet = core.createDescriptorSet(computeShaderProgram.getReflectedDescriptors()[0]);
+    vkcv::DescriptorSetHandle computeDescriptorSet = core.createDescriptorSet(computeShaderProgram.getReflectedDescriptors().at(0));
 
     const std::vector<vkcv::VertexAttachment> computeVertexAttachments = computeShaderProgram.getVertexAttachments();
 
@@ -78,15 +78,15 @@ int main(int argc, const char **argv) {
     const vkcv::VertexLayout computeLayout(computeBindings);
 
     vkcv::ShaderProgram particleShaderProgram{};
-    compiler.compile(vkcv::ShaderStage::VERTEX, "shaders/shader.vert", [&](vkcv::ShaderStage shaderStage, const std::filesystem::path& path) {
+    compiler.compile(vk::ShaderStageFlagBits::eVertex, "shaders/shader.vert", [&](vk::ShaderStageFlagBits shaderStage, const std::filesystem::path& path) {
         particleShaderProgram.addShader(shaderStage, path);
     });
-    compiler.compile(vkcv::ShaderStage::FRAGMENT, useSpace ? "shaders/shader_space.frag" : "shaders/shader_water.frag", [&](vkcv::ShaderStage shaderStage, const std::filesystem::path& path) {
+    compiler.compile(vk::ShaderStageFlagBits::eFragment, useSpace ? "shaders/shader_space.frag" : "shaders/shader_water.frag", [&](vk::ShaderStageFlagBits shaderStage, const std::filesystem::path& path) {
         particleShaderProgram.addShader(shaderStage, path);
     });
 
     vkcv::DescriptorSetHandle descriptorSet = core.createDescriptorSet(
-            particleShaderProgram.getReflectedDescriptors()[0]);
+            particleShaderProgram.getReflectedDescriptors().at(0));
 
     vkcv::Buffer<glm::vec3> vertexBuffer = core.createBuffer<glm::vec3>(
             vkcv::BufferType::VERTEX,
@@ -230,11 +230,11 @@ int main(int argc, const char **argv) {
     });
 
     vkcv::ShaderProgram tonemappingShader;
-    compiler.compile(vkcv::ShaderStage::COMPUTE, "shaders/tonemapping.comp", [&](vkcv::ShaderStage shaderStage, const std::filesystem::path& path) {
+    compiler.compile(vk::ShaderStageFlagBits::eCompute, "shaders/tonemapping.comp", [&](vk::ShaderStageFlagBits shaderStage, const std::filesystem::path& path) {
         tonemappingShader.addShader(shaderStage, path);
     });
 
-    vkcv::DescriptorSetHandle tonemappingDescriptor = core.createDescriptorSet(tonemappingShader.getReflectedDescriptors()[0]);
+    vkcv::DescriptorSetHandle tonemappingDescriptor = core.createDescriptorSet(tonemappingShader.getReflectedDescriptors().at(0));
     vkcv::PipelineHandle tonemappingPipe = core.createComputePipeline(
         tonemappingShader, 
         { core.getDescriptorSet(tonemappingDescriptor).layout });
diff --git a/projects/voxelization/src/BloomAndFlares.cpp b/projects/voxelization/src/BloomAndFlares.cpp
index fac57735a6544c197f880f78e1f512382607d048..c953ef516d9a0176d05ea6bcbba219a756d13b9b 100644
--- a/projects/voxelization/src/BloomAndFlares.cpp
+++ b/projects/voxelization/src/BloomAndFlares.cpp
@@ -36,36 +36,36 @@ BloomAndFlares::BloomAndFlares(
 
     // DOWNSAMPLE
     vkcv::ShaderProgram dsProg;
-    compiler.compile(vkcv::ShaderStage::COMPUTE,
+    compiler.compile(vk::ShaderStageFlagBits::eCompute,
                      "resources/shaders/bloomDownsample.comp",
-                     [&](vkcv::ShaderStage shaderStage, const std::filesystem::path& path)
+                     [&](vk::ShaderStageFlagBits shaderStage, const std::filesystem::path& path)
                      {
                          dsProg.addShader(shaderStage, path);
                      });
     for(uint32_t mipLevel = 0; mipLevel < m_Blur.getMipCount(); mipLevel++)
     {
 		m_DownsampleDescSets.push_back(
-                p_Core->createDescriptorSet(dsProg.getReflectedDescriptors()[0]));
+                p_Core->createDescriptorSet(dsProg.getReflectedDescriptors().at(0)));
     }
     m_DownsamplePipe = p_Core->createComputePipeline(
             dsProg, { p_Core->getDescriptorSet(m_DownsampleDescSets[0]).layout });
 
     // UPSAMPLE
     vkcv::ShaderProgram usProg;
-    compiler.compile(vkcv::ShaderStage::COMPUTE,
+    compiler.compile(vk::ShaderStageFlagBits::eCompute,
                      "resources/shaders/bloomUpsample.comp",
-                     [&](vkcv::ShaderStage shaderStage, const std::filesystem::path& path)
+                     [&](vk::ShaderStageFlagBits shaderStage, const std::filesystem::path& path)
                      {
                          usProg.addShader(shaderStage, path);
                      });
     for(uint32_t mipLevel = 0; mipLevel < m_Blur.getMipCount(); mipLevel++)
     {
         m_UpsampleDescSets.push_back(
-                p_Core->createDescriptorSet(usProg.getReflectedDescriptors()[0]));
+                p_Core->createDescriptorSet(usProg.getReflectedDescriptors().at(0)));
     }
     for (uint32_t mipLevel = 0; mipLevel < m_LensFeatures.getMipCount(); mipLevel++) {
         m_UpsampleLensFlareDescSets.push_back(
-            p_Core->createDescriptorSet(usProg.getReflectedDescriptors()[0]));
+            p_Core->createDescriptorSet(usProg.getReflectedDescriptors().at(0)));
     }
 
     m_UpsamplePipe = p_Core->createComputePipeline(
@@ -73,25 +73,25 @@ BloomAndFlares::BloomAndFlares(
 
     // LENS FEATURES
     vkcv::ShaderProgram lensProg;
-    compiler.compile(vkcv::ShaderStage::COMPUTE,
+    compiler.compile(vk::ShaderStageFlagBits::eCompute,
                      "resources/shaders/lensFlares.comp",
-                     [&](vkcv::ShaderStage shaderStage, const std::filesystem::path& path)
+                     [&](vk::ShaderStageFlagBits shaderStage, const std::filesystem::path& path)
                      {
                          lensProg.addShader(shaderStage, path);
                      });
-    m_LensFlareDescSet = p_Core->createDescriptorSet(lensProg.getReflectedDescriptors()[0]);
+    m_LensFlareDescSet = p_Core->createDescriptorSet(lensProg.getReflectedDescriptors().at(0));
     m_LensFlarePipe = p_Core->createComputePipeline(
             lensProg, { p_Core->getDescriptorSet(m_LensFlareDescSet).layout });
 
     // COMPOSITE
     vkcv::ShaderProgram compProg;
-    compiler.compile(vkcv::ShaderStage::COMPUTE,
+    compiler.compile(vk::ShaderStageFlagBits::eCompute,
                      "resources/shaders/bloomFlaresComposite.comp",
-                     [&](vkcv::ShaderStage shaderStage, const std::filesystem::path& path)
+                     [&](vk::ShaderStageFlagBits shaderStage, const std::filesystem::path& path)
                      {
                          compProg.addShader(shaderStage, path);
                      });
-    m_CompositeDescSet = p_Core->createDescriptorSet(compProg.getReflectedDescriptors()[0]);
+    m_CompositeDescSet = p_Core->createDescriptorSet(compProg.getReflectedDescriptors().at(0));
     m_CompositePipe = p_Core->createComputePipeline(
             compProg, { p_Core->getDescriptorSet(m_CompositeDescSet).layout });
 
diff --git a/projects/voxelization/src/ShadowMapping.cpp b/projects/voxelization/src/ShadowMapping.cpp
index a330394b7bd7ff2a4b8c347bd79e676dbc70f846..ec5b73800e2ea0b2330076b1360a7baad8fae451 100644
--- a/projects/voxelization/src/ShadowMapping.cpp
+++ b/projects/voxelization/src/ShadowMapping.cpp
@@ -9,12 +9,12 @@ const vkcv::Multisampling   msaa                    = vkcv::Multisampling::MSAA8
 vkcv::ShaderProgram loadShadowShader() {
 	vkcv::ShaderProgram shader;
 	vkcv::shader::GLSLCompiler compiler;
-	compiler.compile(vkcv::ShaderStage::VERTEX, "resources/shaders/shadow.vert",
-		[&](vkcv::ShaderStage shaderStage, const std::filesystem::path& path) {
+	compiler.compile(vk::ShaderStageFlagBits::eVertex, "resources/shaders/shadow.vert",
+		[&](vk::ShaderStageFlagBits shaderStage, const std::filesystem::path& path) {
 		shader.addShader(shaderStage, path);
 	});
-	compiler.compile(vkcv::ShaderStage::FRAGMENT, "resources/shaders/shadow.frag",
-		[&](vkcv::ShaderStage shaderStage, const std::filesystem::path& path) {
+	compiler.compile(vk::ShaderStageFlagBits::eFragment, "resources/shaders/shadow.frag",
+		[&](vk::ShaderStageFlagBits shaderStage, const std::filesystem::path& path) {
 		shader.addShader(shaderStage, path);
 	});
 	return shader;
@@ -23,8 +23,8 @@ vkcv::ShaderProgram loadShadowShader() {
 vkcv::ShaderProgram loadDepthToMomentsShader() {
 	vkcv::ShaderProgram shader;
 	vkcv::shader::GLSLCompiler compiler;
-	compiler.compile(vkcv::ShaderStage::COMPUTE, "resources/shaders/depthToMoments.comp",
-		[&](vkcv::ShaderStage shaderStage, const std::filesystem::path& path) {
+	compiler.compile(vk::ShaderStageFlagBits::eCompute, "resources/shaders/depthToMoments.comp",
+		[&](vk::ShaderStageFlagBits shaderStage, const std::filesystem::path& path) {
 		shader.addShader(shaderStage, path);
 	});
 	return shader;
@@ -33,8 +33,8 @@ vkcv::ShaderProgram loadDepthToMomentsShader() {
 vkcv::ShaderProgram loadShadowBlurXShader() {
 	vkcv::ShaderProgram shader;
 	vkcv::shader::GLSLCompiler compiler;
-	compiler.compile(vkcv::ShaderStage::COMPUTE, "resources/shaders/shadowBlurX.comp",
-		[&](vkcv::ShaderStage shaderStage, const std::filesystem::path& path) {
+	compiler.compile(vk::ShaderStageFlagBits::eCompute, "resources/shaders/shadowBlurX.comp",
+		[&](vk::ShaderStageFlagBits shaderStage, const std::filesystem::path& path) {
 		shader.addShader(shaderStage, path);
 	});
 	return shader;
@@ -43,8 +43,8 @@ vkcv::ShaderProgram loadShadowBlurXShader() {
 vkcv::ShaderProgram loadShadowBlurYShader() {
 	vkcv::ShaderProgram shader;
 	vkcv::shader::GLSLCompiler compiler;
-	compiler.compile(vkcv::ShaderStage::COMPUTE, "resources/shaders/shadowBlurY.comp",
-		[&](vkcv::ShaderStage shaderStage, const std::filesystem::path& path) {
+	compiler.compile(vk::ShaderStageFlagBits::eCompute, "resources/shaders/shadowBlurY.comp",
+		[&](vk::ShaderStageFlagBits shaderStage, const std::filesystem::path& path) {
 		shader.addShader(shaderStage, path);
 	});
 	return shader;
@@ -189,7 +189,7 @@ ShadowMapping::ShadowMapping(vkcv::Core* corePtr, const vkcv::VertexLayout& vert
 
 	// depth to moments
 	vkcv::ShaderProgram depthToMomentsShader    = loadDepthToMomentsShader();
-	m_depthToMomentsDescriptorSet               = corePtr->createDescriptorSet(depthToMomentsShader.getReflectedDescriptors()[0]);
+	m_depthToMomentsDescriptorSet               = corePtr->createDescriptorSet(depthToMomentsShader.getReflectedDescriptors().at(0));
 	m_depthToMomentsPipe                        = corePtr->createComputePipeline(depthToMomentsShader, { corePtr->getDescriptorSet(m_depthToMomentsDescriptorSet).layout });
 
 	vkcv::DescriptorWrites depthToMomentDescriptorWrites;
@@ -200,7 +200,7 @@ ShadowMapping::ShadowMapping(vkcv::Core* corePtr, const vkcv::VertexLayout& vert
 
 	// shadow blur X
 	vkcv::ShaderProgram shadowBlurXShader    = loadShadowBlurXShader();
-	m_shadowBlurXDescriptorSet              = corePtr->createDescriptorSet(shadowBlurXShader.getReflectedDescriptors()[0]);
+	m_shadowBlurXDescriptorSet              = corePtr->createDescriptorSet(shadowBlurXShader.getReflectedDescriptors().at(0));
 	m_shadowBlurXPipe                       = corePtr->createComputePipeline(shadowBlurXShader, { corePtr->getDescriptorSet(m_shadowBlurXDescriptorSet).layout });
 
 	vkcv::DescriptorWrites shadowBlurXDescriptorWrites;
@@ -211,7 +211,7 @@ ShadowMapping::ShadowMapping(vkcv::Core* corePtr, const vkcv::VertexLayout& vert
 
 	// shadow blur Y
 	vkcv::ShaderProgram shadowBlurYShader = loadShadowBlurYShader();
-	m_shadowBlurYDescriptorSet = corePtr->createDescriptorSet(shadowBlurYShader.getReflectedDescriptors()[0]);
+	m_shadowBlurYDescriptorSet = corePtr->createDescriptorSet(shadowBlurYShader.getReflectedDescriptors().at(0));
 	m_shadowBlurYPipe = corePtr->createComputePipeline(shadowBlurYShader, { corePtr->getDescriptorSet(m_shadowBlurYDescriptorSet).layout });
 
 	vkcv::DescriptorWrites shadowBlurYDescriptorWrites;
diff --git a/projects/voxelization/src/Voxelization.cpp b/projects/voxelization/src/Voxelization.cpp
index c117b4b9e6b896fbf51aae83343f30281061be9f..9ef4e87497e86221e0e2e9ad6ea733db778a393d 100644
--- a/projects/voxelization/src/Voxelization.cpp
+++ b/projects/voxelization/src/Voxelization.cpp
@@ -6,16 +6,16 @@
 vkcv::ShaderProgram loadVoxelizationShader() {
 	vkcv::shader::GLSLCompiler compiler;
 	vkcv::ShaderProgram shader;
-	compiler.compile(vkcv::ShaderStage::VERTEX, "resources/shaders/voxelization.vert",
-		[&](vkcv::ShaderStage shaderStage, const std::filesystem::path& path) {
+	compiler.compile(vk::ShaderStageFlagBits::eVertex, "resources/shaders/voxelization.vert",
+		[&](vk::ShaderStageFlagBits shaderStage, const std::filesystem::path& path) {
 		shader.addShader(shaderStage, path);
 	});
-	compiler.compile(vkcv::ShaderStage::GEOMETRY, "resources/shaders/voxelization.geom",
-		[&](vkcv::ShaderStage shaderStage, const std::filesystem::path& path) {
+	compiler.compile(vk::ShaderStageFlagBits::eGeometry, "resources/shaders/voxelization.geom",
+		[&](vk::ShaderStageFlagBits shaderStage, const std::filesystem::path& path) {
 		shader.addShader(shaderStage, path);
 	});
-	compiler.compile(vkcv::ShaderStage::FRAGMENT, "resources/shaders/voxelization.frag",
-		[&](vkcv::ShaderStage shaderStage, const std::filesystem::path& path) {
+	compiler.compile(vk::ShaderStageFlagBits::eFragment, "resources/shaders/voxelization.frag",
+		[&](vk::ShaderStageFlagBits shaderStage, const std::filesystem::path& path) {
 		shader.addShader(shaderStage, path);
 	});
 	return shader;
@@ -24,16 +24,16 @@ vkcv::ShaderProgram loadVoxelizationShader() {
 vkcv::ShaderProgram loadVoxelVisualisationShader() {
 	vkcv::shader::GLSLCompiler compiler;
 	vkcv::ShaderProgram shader;
-	compiler.compile(vkcv::ShaderStage::VERTEX, "resources/shaders/voxelVisualisation.vert",
-		[&](vkcv::ShaderStage shaderStage, const std::filesystem::path& path) {
+	compiler.compile(vk::ShaderStageFlagBits::eVertex, "resources/shaders/voxelVisualisation.vert",
+		[&](vk::ShaderStageFlagBits shaderStage, const std::filesystem::path& path) {
 		shader.addShader(shaderStage, path);
 	});
-	compiler.compile(vkcv::ShaderStage::GEOMETRY, "resources/shaders/voxelVisualisation.geom",
-		[&](vkcv::ShaderStage shaderStage, const std::filesystem::path& path) {
+	compiler.compile(vk::ShaderStageFlagBits::eGeometry, "resources/shaders/voxelVisualisation.geom",
+		[&](vk::ShaderStageFlagBits shaderStage, const std::filesystem::path& path) {
 		shader.addShader(shaderStage, path);
 	});
-	compiler.compile(vkcv::ShaderStage::FRAGMENT, "resources/shaders/voxelVisualisation.frag",
-		[&](vkcv::ShaderStage shaderStage, const std::filesystem::path& path) {
+	compiler.compile(vk::ShaderStageFlagBits::eFragment, "resources/shaders/voxelVisualisation.frag",
+		[&](vk::ShaderStageFlagBits shaderStage, const std::filesystem::path& path) {
 		shader.addShader(shaderStage, path);
 	});
 	return shader;
@@ -42,8 +42,8 @@ vkcv::ShaderProgram loadVoxelVisualisationShader() {
 vkcv::ShaderProgram loadVoxelResetShader() {
 	vkcv::shader::GLSLCompiler compiler;
 	vkcv::ShaderProgram shader;
-	compiler.compile(vkcv::ShaderStage::COMPUTE, "resources/shaders/voxelReset.comp",
-		[&](vkcv::ShaderStage shaderStage, const std::filesystem::path& path) {
+	compiler.compile(vk::ShaderStageFlagBits::eCompute, "resources/shaders/voxelReset.comp",
+		[&](vk::ShaderStageFlagBits shaderStage, const std::filesystem::path& path) {
 		shader.addShader(shaderStage, path);
 	});
 	return shader;
@@ -52,8 +52,8 @@ vkcv::ShaderProgram loadVoxelResetShader() {
 vkcv::ShaderProgram loadVoxelBufferToImageShader() {
 	vkcv::shader::GLSLCompiler compiler;
 	vkcv::ShaderProgram shader;
-	compiler.compile(vkcv::ShaderStage::COMPUTE, "resources/shaders/voxelBufferToImage.comp",
-		[&](vkcv::ShaderStage shaderStage, const std::filesystem::path& path) {
+	compiler.compile(vk::ShaderStageFlagBits::eCompute, "resources/shaders/voxelBufferToImage.comp",
+		[&](vk::ShaderStageFlagBits shaderStage, const std::filesystem::path& path) {
 		shader.addShader(shaderStage, path);
 	});
 	return shader;
@@ -62,8 +62,8 @@ vkcv::ShaderProgram loadVoxelBufferToImageShader() {
 vkcv::ShaderProgram loadSecondaryBounceShader() {
 	vkcv::shader::GLSLCompiler compiler;
 	vkcv::ShaderProgram shader;
-	compiler.compile(vkcv::ShaderStage::COMPUTE, "resources/shaders/voxelSecondaryBounce.comp",
-		[&](vkcv::ShaderStage shaderStage, const std::filesystem::path& path) {
+	compiler.compile(vk::ShaderStageFlagBits::eCompute, "resources/shaders/voxelSecondaryBounce.comp",
+		[&](vk::ShaderStageFlagBits shaderStage, const std::filesystem::path& path) {
 		shader.addShader(shaderStage, path);
 	});
 	return shader;
@@ -98,12 +98,10 @@ Voxelization::Voxelization(
 		voxelizationDummyFormat) });
 	m_voxelizationPass = m_corePtr->createPass(voxelizationPassConfig);
 
-	std::vector<vkcv::DescriptorBinding> voxelizationDescriptorBindings = 
-	{ voxelizationShader.getReflectedDescriptors()[0] };
-	m_voxelizationDescriptorSet = m_corePtr->createDescriptorSet(voxelizationDescriptorBindings);
+	m_voxelizationDescriptorSet = m_corePtr->createDescriptorSet(voxelizationShader.getReflectedDescriptors().at(0));
 
 	vkcv::DescriptorSetHandle dummyPerMeshDescriptorSet =
-		m_corePtr->createDescriptorSet({ voxelizationShader.getReflectedDescriptors()[1] });
+		m_corePtr->createDescriptorSet({ voxelizationShader.getReflectedDescriptors().at(1) });
 
 	const vkcv::PipelineConfig voxelizationPipeConfig{
 		voxelizationShader,
@@ -131,9 +129,7 @@ Voxelization::Voxelization(
 
 	vkcv::ShaderProgram voxelVisualisationShader = loadVoxelVisualisationShader();
 
-	const std::vector<vkcv::DescriptorBinding> voxelVisualisationDescriptorBindings = 
-		{ voxelVisualisationShader.getReflectedDescriptors()[0] };
-	m_visualisationDescriptorSet = m_corePtr->createDescriptorSet(voxelVisualisationDescriptorBindings);
+	m_visualisationDescriptorSet = m_corePtr->createDescriptorSet(voxelVisualisationShader.getReflectedDescriptors().at(0));
 
 	const vkcv::AttachmentDescription voxelVisualisationColorAttachments(
 		vkcv::AttachmentOperation::STORE,
@@ -174,7 +170,7 @@ Voxelization::Voxelization(
 
 	vkcv::ShaderProgram resetVoxelShader = loadVoxelResetShader();
 
-	m_voxelResetDescriptorSet = m_corePtr->createDescriptorSet(resetVoxelShader.getReflectedDescriptors()[0]);
+	m_voxelResetDescriptorSet = m_corePtr->createDescriptorSet(resetVoxelShader.getReflectedDescriptors().at(0));
 	m_voxelResetPipe = m_corePtr->createComputePipeline(
 		resetVoxelShader,
 		{ m_corePtr->getDescriptorSet(m_voxelResetDescriptorSet).layout });
@@ -186,7 +182,7 @@ Voxelization::Voxelization(
 	// buffer to image
 	vkcv::ShaderProgram bufferToImageShader = loadVoxelBufferToImageShader();
 
-	m_bufferToImageDescriptorSet = m_corePtr->createDescriptorSet(bufferToImageShader.getReflectedDescriptors()[0]);
+	m_bufferToImageDescriptorSet = m_corePtr->createDescriptorSet(bufferToImageShader.getReflectedDescriptors().at(0));
 	m_bufferToImagePipe = m_corePtr->createComputePipeline(
 		bufferToImageShader,
 		{ m_corePtr->getDescriptorSet(m_bufferToImageDescriptorSet).layout });
@@ -199,7 +195,7 @@ Voxelization::Voxelization(
 	// secondary bounce
 	vkcv::ShaderProgram secondaryBounceShader = loadSecondaryBounceShader();
 
-	m_secondaryBounceDescriptorSet = m_corePtr->createDescriptorSet(secondaryBounceShader.getReflectedDescriptors()[0]);
+	m_secondaryBounceDescriptorSet = m_corePtr->createDescriptorSet(secondaryBounceShader.getReflectedDescriptors().at(0));
 	m_secondaryBouncePipe = m_corePtr->createComputePipeline(
 		secondaryBounceShader,
 		{ m_corePtr->getDescriptorSet(m_secondaryBounceDescriptorSet).layout });
diff --git a/projects/voxelization/src/main.cpp b/projects/voxelization/src/main.cpp
index edc50c554b6c73bd2f06914eba6dd7adf9e43483..a3248c384f7c7199be26d955dfcc4a8a50a1a8a3 100644
--- a/projects/voxelization/src/main.cpp
+++ b/projects/voxelization/src/main.cpp
@@ -171,12 +171,12 @@ int main(int argc, const char** argv) {
 	vkcv::shader::GLSLCompiler compiler;
 
 	vkcv::ShaderProgram forwardProgram;
-	compiler.compile(vkcv::ShaderStage::VERTEX, std::filesystem::path("resources/shaders/shader.vert"), 
-		[&](vkcv::ShaderStage shaderStage, const std::filesystem::path& path) {
+	compiler.compile(vk::ShaderStageFlagBits::eVertex, std::filesystem::path("resources/shaders/shader.vert"),
+		[&](vk::ShaderStageFlagBits shaderStage, const std::filesystem::path& path) {
 		forwardProgram.addShader(shaderStage, path);
 	});
-	compiler.compile(vkcv::ShaderStage::FRAGMENT, std::filesystem::path("resources/shaders/shader.frag"),
-		[&](vkcv::ShaderStage shaderStage, const std::filesystem::path& path) {
+	compiler.compile(vk::ShaderStageFlagBits::eFragment, std::filesystem::path("resources/shaders/shader.frag"),
+		[&](vk::ShaderStageFlagBits shaderStage, const std::filesystem::path& path) {
 		forwardProgram.addShader(shaderStage, path);
 	});
 
@@ -189,16 +189,16 @@ int main(int argc, const char** argv) {
 	const vkcv::VertexLayout vertexLayout (vertexBindings);
 
 	vkcv::DescriptorSetHandle forwardShadingDescriptorSet = 
-		core.createDescriptorSet({ forwardProgram.getReflectedDescriptors()[0] });
+		core.createDescriptorSet(forwardProgram.getReflectedDescriptors().at(0));
 
 	// depth prepass config
 	vkcv::ShaderProgram depthPrepassShader;
-	compiler.compile(vkcv::ShaderStage::VERTEX, std::filesystem::path("resources/shaders/depthPrepass.vert"),
-		[&](vkcv::ShaderStage shaderStage, const std::filesystem::path& path) {
+	compiler.compile(vk::ShaderStageFlagBits::eVertex, std::filesystem::path("resources/shaders/depthPrepass.vert"),
+		[&](vk::ShaderStageFlagBits shaderStage, const std::filesystem::path& path) {
 		depthPrepassShader.addShader(shaderStage, path);
 	});
-	compiler.compile(vkcv::ShaderStage::FRAGMENT, std::filesystem::path("resources/shaders/depthPrepass.frag"),
-		[&](vkcv::ShaderStage shaderStage, const std::filesystem::path& path) {
+	compiler.compile(vk::ShaderStageFlagBits::eFragment, std::filesystem::path("resources/shaders/depthPrepass.frag"),
+		[&](vk::ShaderStageFlagBits shaderStage, const std::filesystem::path& path) {
 		depthPrepassShader.addShader(shaderStage, path);
 	});
 
@@ -247,7 +247,7 @@ int main(int argc, const char** argv) {
 			specularIndex = 0;
 		}
 
-		materialDescriptorSets.push_back(core.createDescriptorSet(forwardProgram.getReflectedDescriptors()[1]));
+		materialDescriptorSets.push_back(core.createDescriptorSet(forwardProgram.getReflectedDescriptors().at(1)));
 
 		vkcv::asset::Texture& albedoTexture     = scene.textures[albedoIndex];
 		vkcv::asset::Texture& normalTexture     = scene.textures[normalIndex];
@@ -292,7 +292,7 @@ int main(int argc, const char** argv) {
 	}
 
 	// prepass pipeline
-	vkcv::DescriptorSetHandle prepassDescriptorSet = core.createDescriptorSet(std::vector<vkcv::DescriptorBinding>());
+	vkcv::DescriptorSetHandle prepassDescriptorSet = core.createDescriptorSet({});
 
 	vkcv::PipelineConfig prepassPipelineConfig{
 		depthPrepassShader,
@@ -358,12 +358,12 @@ int main(int argc, const char** argv) {
 	vkcv::PassHandle skyPass = core.createPass(skyPassConfig);
 
 	vkcv::ShaderProgram skyShader;
-	compiler.compile(vkcv::ShaderStage::VERTEX, std::filesystem::path("resources/shaders/sky.vert"),
-		[&](vkcv::ShaderStage shaderStage, const std::filesystem::path& path) {
+	compiler.compile(vk::ShaderStageFlagBits::eVertex, std::filesystem::path("resources/shaders/sky.vert"),
+		[&](vk::ShaderStageFlagBits shaderStage, const std::filesystem::path& path) {
 		skyShader.addShader(shaderStage, path);
 	});
-	compiler.compile(vkcv::ShaderStage::FRAGMENT, std::filesystem::path("resources/shaders/sky.frag"),
-		[&](vkcv::ShaderStage shaderStage, const std::filesystem::path& path) {
+	compiler.compile(vk::ShaderStageFlagBits::eFragment, std::filesystem::path("resources/shaders/sky.frag"),
+		[&](vk::ShaderStageFlagBits shaderStage, const std::filesystem::path& path) {
 		skyShader.addShader(shaderStage, path);
 	});
 
@@ -412,24 +412,24 @@ int main(int argc, const char** argv) {
 
 	// tonemapping compute shader
 	vkcv::ShaderProgram tonemappingProgram;
-	compiler.compile(vkcv::ShaderStage::COMPUTE, "resources/shaders/tonemapping.comp", 
-		[&](vkcv::ShaderStage shaderStage, const std::filesystem::path& path) {
+	compiler.compile(vk::ShaderStageFlagBits::eCompute, "resources/shaders/tonemapping.comp",
+		[&](vk::ShaderStageFlagBits shaderStage, const std::filesystem::path& path) {
 		tonemappingProgram.addShader(shaderStage, path);
 	});
 	vkcv::DescriptorSetHandle tonemappingDescriptorSet = core.createDescriptorSet(
-		tonemappingProgram.getReflectedDescriptors()[0]);
+		tonemappingProgram.getReflectedDescriptors().at(0));
 	vkcv::PipelineHandle tonemappingPipeline = core.createComputePipeline(
 		tonemappingProgram,
 		{ core.getDescriptorSet(tonemappingDescriptorSet).layout });
 
 	// resolve compute shader
 	vkcv::ShaderProgram resolveProgram;
-	compiler.compile(vkcv::ShaderStage::COMPUTE, "resources/shaders/msaa4XResolve.comp",
-		[&](vkcv::ShaderStage shaderStage, const std::filesystem::path& path) {
+	compiler.compile(vk::ShaderStageFlagBits::eCompute, "resources/shaders/msaa4XResolve.comp",
+		[&](vk::ShaderStageFlagBits shaderStage, const std::filesystem::path& path) {
 		resolveProgram.addShader(shaderStage, path);
 	});
 	vkcv::DescriptorSetHandle resolveDescriptorSet = core.createDescriptorSet(
-		resolveProgram.getReflectedDescriptors()[0]);
+		resolveProgram.getReflectedDescriptors().at(0));
 	vkcv::PipelineHandle resolvePipeline = core.createComputePipeline(
 		resolveProgram,
 		{ core.getDescriptorSet(resolveDescriptorSet).layout });
@@ -753,12 +753,12 @@ int main(int argc, const char** argv) {
 			if (ImGui::Button("Reload forward pass")) {
 
 				vkcv::ShaderProgram newForwardProgram;
-				compiler.compile(vkcv::ShaderStage::VERTEX, std::filesystem::path("resources/shaders/shader.vert"),
-					[&](vkcv::ShaderStage shaderStage, const std::filesystem::path& path) {
+				compiler.compile(vk::ShaderStageFlagBits::eVertex, std::filesystem::path("resources/shaders/shader.vert"),
+					[&](vk::ShaderStageFlagBits shaderStage, const std::filesystem::path& path) {
 					newForwardProgram.addShader(shaderStage, path);
 				});
-				compiler.compile(vkcv::ShaderStage::FRAGMENT, std::filesystem::path("resources/shaders/shader.frag"),
-					[&](vkcv::ShaderStage shaderStage, const std::filesystem::path& path) {
+				compiler.compile(vk::ShaderStageFlagBits::eFragment, std::filesystem::path("resources/shaders/shader.frag"),
+					[&](vk::ShaderStageFlagBits shaderStage, const std::filesystem::path& path) {
 					newForwardProgram.addShader(shaderStage, path);
 				});
 				forwardPipelineConfig.m_ShaderProgram = newForwardProgram;
@@ -771,8 +771,8 @@ int main(int argc, const char** argv) {
 			if (ImGui::Button("Reload tonemapping")) {
 
 				vkcv::ShaderProgram newProgram;
-				compiler.compile(vkcv::ShaderStage::COMPUTE, std::filesystem::path("resources/shaders/tonemapping.comp"),
-					[&](vkcv::ShaderStage shaderStage, const std::filesystem::path& path) {
+				compiler.compile(vk::ShaderStageFlagBits::eCompute, std::filesystem::path("resources/shaders/tonemapping.comp"),
+					[&](vk::ShaderStageFlagBits shaderStage, const std::filesystem::path& path) {
 					newProgram.addShader(shaderStage, path);
 				});
 				vkcv::PipelineHandle newPipeline = core.createComputePipeline(
diff --git a/src/vkcv/Core.cpp b/src/vkcv/Core.cpp
index 352a1cf62eabe55ce1bbf2f53a6b5a4bd6e91753..39692a01a1236a3a07f2788c8bf67eadc6a34845 100644
--- a/src/vkcv/Core.cpp
+++ b/src/vkcv/Core.cpp
@@ -532,7 +532,7 @@ namespace vkcv
 		return m_ImageManager->getImageHeight(imageHandle);
 	}
 
-    DescriptorSetHandle Core::createDescriptorSet(const std::vector<DescriptorBinding>& bindings)
+    DescriptorSetHandle Core::createDescriptorSet(const std::unordered_map<uint32_t, DescriptorBinding>& bindings)
     {
         return m_DescriptorManager->createDescriptorSet(bindings);
     }
diff --git a/src/vkcv/DescriptorConfig.cpp b/src/vkcv/DescriptorConfig.cpp
index a9a127fe608472682c1cbc8d32ca466fba860c72..1fc075ced91aebe4a5d3596c635208368db08822 100644
--- a/src/vkcv/DescriptorConfig.cpp
+++ b/src/vkcv/DescriptorConfig.cpp
@@ -5,7 +5,7 @@ namespace vkcv {
 		uint32_t bindingID,
 		DescriptorType descriptorType,
 		uint32_t descriptorCount,
-		ShaderStages shaderStages) noexcept
+		vk::ShaderStageFlags shaderStages) noexcept
 		:
 		bindingID(bindingID),
 		descriptorType(descriptorType),
diff --git a/src/vkcv/DescriptorManager.cpp b/src/vkcv/DescriptorManager.cpp
index d28dd9d137240ba923b55c9be9da9059d3a9ab31..5197adc773a5a8961c02da8d622504926b6b1be6 100644
--- a/src/vkcv/DescriptorManager.cpp
+++ b/src/vkcv/DescriptorManager.cpp
@@ -35,17 +35,17 @@ namespace vkcv
 		}
     }
 
-    DescriptorSetHandle DescriptorManager::createDescriptorSet(const std::vector<DescriptorBinding>& bindings)
+    DescriptorSetHandle DescriptorManager::createDescriptorSet(const std::unordered_map<uint32_t, DescriptorBinding>& bindings)
     {
         std::vector<vk::DescriptorSetLayoutBinding> setBindings = {};
 
-        //create each set's binding
-        for (uint32_t i = 0; i < bindings.size(); i++) {
+        //create the set's bindings
+		for (auto bindingIter = bindings.begin(); bindingIter != bindings.end(); bindingIter++) {
             vk::DescriptorSetLayoutBinding descriptorSetLayoutBinding(
-                bindings[i].bindingID,
-                convertDescriptorTypeFlag(bindings[i].descriptorType),
-                bindings[i].descriptorCount,
-				getShaderStageFlags(bindings[i].shaderStages));
+				bindingIter->second.bindingID,
+                convertDescriptorTypeFlag(bindingIter->second.descriptorType),
+				bindingIter->second.descriptorCount,
+				bindingIter->second.shaderStages);
             setBindings.push_back(descriptorSetLayoutBinding);
         }
 
diff --git a/src/vkcv/DescriptorManager.hpp b/src/vkcv/DescriptorManager.hpp
index df58daa56c26a0432f365a4ed0d9df56adc4cd0e..90ad43b3dafac8822c9df54e34dea14834160521 100644
--- a/src/vkcv/DescriptorManager.hpp
+++ b/src/vkcv/DescriptorManager.hpp
@@ -1,5 +1,5 @@
 /**
- * @authors Artur Wasmut, Susanne D�tsch, Simeon Hermann
+ * @authors Artur Wasmut, Susanne Dötsch, Simeon Hermann
  * @file src/vkcv/DescriptorManager.cpp
  * @brief Creation and handling of descriptor sets and the respective descriptor pools
  */
@@ -21,7 +21,7 @@ namespace vkcv
 	    explicit DescriptorManager(vk::Device device) noexcept;
 	    ~DescriptorManager() noexcept;
 
-        DescriptorSetHandle createDescriptorSet(const std::vector<DescriptorBinding> &descriptorBindings);
+        DescriptorSetHandle createDescriptorSet(const std::unordered_map<uint32_t, DescriptorBinding> &descriptorBindings);
 
 		void writeDescriptorSet(
 			const DescriptorSetHandle	&handle,
diff --git a/src/vkcv/PipelineManager.cpp b/src/vkcv/PipelineManager.cpp
index 8b1f0b68be3a72f60103ca0dd8136f2c923513a5..0e35c2db5db91dd19770d0628102923b38544185 100644
--- a/src/vkcv/PipelineManager.cpp
+++ b/src/vkcv/PipelineManager.cpp
@@ -67,8 +67,8 @@ namespace vkcv
     {
 		const vk::RenderPass &pass = passManager.getVkPass(config.m_PassHandle);
     	
-        const bool existsVertexShader = config.m_ShaderProgram.existsShader(ShaderStage::VERTEX);
-        const bool existsFragmentShader = config.m_ShaderProgram.existsShader(ShaderStage::FRAGMENT);
+        const bool existsVertexShader = config.m_ShaderProgram.existsShader(vk::ShaderStageFlagBits::eVertex);
+        const bool existsFragmentShader = config.m_ShaderProgram.existsShader(vk::ShaderStageFlagBits::eFragment);
         if (!(existsVertexShader && existsFragmentShader))
         {
 			vkcv_log(LogLevel::ERROR, "Requires vertex and fragment shader code");
@@ -76,7 +76,7 @@ namespace vkcv
         }
 
         // vertex shader stage
-        std::vector<char> vertexCode = config.m_ShaderProgram.getShader(ShaderStage::VERTEX).shaderCode;
+        std::vector<char> vertexCode = config.m_ShaderProgram.getShader(vk::ShaderStageFlagBits::eVertex).shaderCode;
         vk::ShaderModuleCreateInfo vertexModuleInfo({}, vertexCode.size(), reinterpret_cast<uint32_t*>(vertexCode.data()));
         vk::ShaderModule vertexModule{};
         if (m_Device.createShaderModule(&vertexModuleInfo, nullptr, &vertexModule) != vk::Result::eSuccess)
@@ -91,7 +91,7 @@ namespace vkcv
         );
 
         // fragment shader stage
-        std::vector<char> fragCode = config.m_ShaderProgram.getShader(ShaderStage::FRAGMENT).shaderCode;
+        std::vector<char> fragCode = config.m_ShaderProgram.getShader(vk::ShaderStageFlagBits::eFragment).shaderCode;
         vk::ShaderModuleCreateInfo fragmentModuleInfo({}, fragCode.size(), reinterpret_cast<uint32_t*>(fragCode.data()));
         vk::ShaderModule fragmentModule{};
         if (m_Device.createShaderModule(&fragmentModuleInfo, nullptr, &fragmentModule) != vk::Result::eSuccess)
@@ -285,8 +285,8 @@ namespace vkcv
 
 		const char *geometryShaderName = "main";	// outside of if to make sure it stays in scope
 		vk::ShaderModule geometryModule;
-		if (config.m_ShaderProgram.existsShader(ShaderStage::GEOMETRY)) {
-			const vkcv::Shader geometryShader = config.m_ShaderProgram.getShader(ShaderStage::GEOMETRY);
+		if (config.m_ShaderProgram.existsShader(vk::ShaderStageFlagBits::eGeometry)) {
+			const vkcv::Shader geometryShader = config.m_ShaderProgram.getShader(vk::ShaderStageFlagBits::eGeometry);
 			const auto& geometryCode = geometryShader.shaderCode;
 			const vk::ShaderModuleCreateInfo geometryModuleInfo({}, geometryCode.size(), reinterpret_cast<const uint32_t*>(geometryCode.data()));
 			if (m_Device.createShaderModule(&geometryModuleInfo, nullptr, &geometryModule) != vk::Result::eSuccess) {
@@ -402,7 +402,7 @@ namespace vkcv
 
         // Temporally handing over the Shader Program instead of a pipeline config
         vk::ShaderModule computeModule{};
-        if (createShaderModule(computeModule, shaderProgram, ShaderStage::COMPUTE) != vk::Result::eSuccess)
+        if (createShaderModule(computeModule, shaderProgram, vk::ShaderStageFlagBits::eCompute) != vk::Result::eSuccess)
             return PipelineHandle();
 
         vk::PipelineShaderStageCreateInfo pipelineComputeShaderStageInfo(
@@ -451,7 +451,7 @@ namespace vkcv
     // There is an issue for refactoring the Pipeline Manager.
     // While including Compute Pipeline Creation, some private helper functions where introduced:
 
-    vk::Result PipelineManager::createShaderModule(vk::ShaderModule &module, const ShaderProgram &shaderProgram, const ShaderStage stage)
+    vk::Result PipelineManager::createShaderModule(vk::ShaderModule &module, const ShaderProgram &shaderProgram, const vk::ShaderStageFlagBits stage)
     {
         std::vector<char> code = shaderProgram.getShader(stage).shaderCode;
         vk::ShaderModuleCreateInfo moduleInfo({}, code.size(), reinterpret_cast<uint32_t*>(code.data()));
diff --git a/src/vkcv/PipelineManager.hpp b/src/vkcv/PipelineManager.hpp
index b153eb4632b844e84b92953fe8abf6666a13e0c9..b48e06f07de6b863ae79a810482a355f5e4e280a 100644
--- a/src/vkcv/PipelineManager.hpp
+++ b/src/vkcv/PipelineManager.hpp
@@ -22,7 +22,7 @@ namespace vkcv
         
         void destroyPipelineById(uint64_t id);
 
-        vk::Result createShaderModule(vk::ShaderModule &module, const ShaderProgram &shaderProgram, ShaderStage stage);
+        vk::Result createShaderModule(vk::ShaderModule &module, const ShaderProgram &shaderProgram, vk::ShaderStageFlagBits stage);
 
     public:
         PipelineManager() = delete; // no default ctor
diff --git a/src/vkcv/ShaderProgram.cpp b/src/vkcv/ShaderProgram.cpp
index 134ba7afd203d3222b37dfaf627a9d4fd3ede1c7..5225b56735944b2d52d08bcf26c02bd2cb177ec5 100644
--- a/src/vkcv/ShaderProgram.cpp
+++ b/src/vkcv/ShaderProgram.cpp
@@ -76,7 +76,7 @@ namespace vkcv {
     m_DescriptorSets{}
 	{}
 
-	bool ShaderProgram::addShader(ShaderStage shaderStage, const std::filesystem::path &shaderPath)
+	bool ShaderProgram::addShader(vk::ShaderStageFlagBits shaderStage, const std::filesystem::path &shaderPath)
 	{
 	    if(m_Shaders.find(shaderStage) != m_Shaders.end()) {
 			vkcv_log(LogLevel::WARNING, "Overwriting existing shader stage");
@@ -94,12 +94,12 @@ namespace vkcv {
         }
 	}
 
-    const Shader &ShaderProgram::getShader(ShaderStage shaderStage) const
+    const Shader &ShaderProgram::getShader(vk::ShaderStageFlagBits shaderStage) const
     {
 	    return m_Shaders.at(shaderStage);
 	}
 
-    bool ShaderProgram::existsShader(ShaderStage shaderStage) const
+    bool ShaderProgram::existsShader(vk::ShaderStageFlagBits shaderStage) const
     {
 	    if(m_Shaders.find(shaderStage) == m_Shaders.end())
 	        return false;
@@ -107,7 +107,7 @@ namespace vkcv {
 	        return true;
     }
 
-    void ShaderProgram::reflectShader(ShaderStage shaderStage)
+    void ShaderProgram::reflectShader(vk::ShaderStageFlagBits shaderStage)
     {
         auto shaderCodeChar = m_Shaders.at(shaderStage).shaderCode;
         std::vector<uint32_t> shaderCode;
@@ -119,7 +119,7 @@ namespace vkcv {
         spirv_cross::ShaderResources resources = comp.get_shader_resources();
 
         //reflect vertex input
-		if (shaderStage == ShaderStage::VERTEX)
+		if (shaderStage == vk::ShaderStageFlagBits::eVertex)
 		{
 			// spirv-cross API (hopefully) returns the stage_inputs in order
 			for (uint32_t i = 0; i < resources.stage_inputs.size(); i++)
@@ -140,80 +140,195 @@ namespace vkcv {
 		}
 
 		//reflect descriptor sets (uniform buffer, storage buffer, sampler, sampled image, storage image)
-        std::vector<std::pair<uint32_t, DescriptorBinding>> bindings;
+        // std::vector<std::pair<uint32_t, DescriptorBinding>> bindings;
         int32_t maxSetID = -1;
         for (uint32_t i = 0; i < resources.uniform_buffers.size(); i++) {
             auto& u = resources.uniform_buffers[i];
             const spirv_cross::SPIRType& base_type = comp.get_type(u.base_type_id);
-            std::pair descriptor(comp.get_decoration(u.id, spv::DecorationDescriptorSet),
-                DescriptorBinding(comp.get_decoration(u.id, spv::DecorationBinding), DescriptorType::UNIFORM_BUFFER, base_type.vecsize, shaderStage));
-            bindings.push_back(descriptor);
-            if ((int32_t)comp.get_decoration(u.id, spv::DecorationDescriptorSet) > maxSetID) 
-                maxSetID = comp.get_decoration(u.id, spv::DecorationDescriptorSet);
+
+            const uint32_t setID = comp.get_decoration(u.id, spv::DecorationDescriptorSet);
+            const uint32_t bindingID = comp.get_decoration(u.id, spv::DecorationBinding);
+
+            const DescriptorBinding binding(bindingID, DescriptorType::UNIFORM_BUFFER, base_type.vecsize, shaderStage);
+
+            auto setIter = m_DescriptorSets.find(setID);
+            if (setIter == m_DescriptorSets.end())
+            {
+                // create a map for this set ID
+                std::unordered_map<uint32_t, DescriptorBinding> setBindings;
+                // insert the binding to this set ID's bindings
+                setBindings.insert(std::make_pair(bindingID, binding));
+                // insert this set ID's map to the descriptor sets
+                m_DescriptorSets.insert(std::make_pair(setID, setBindings));
+            }
+            else
+            {
+                // search for an existing binding for this set
+                auto bindingIter = setIter->second.find(bindingID);
+                if (bindingIter == setIter->second.end())
+                {
+                    // if binding did not exist, insert it
+                    setIter->second.insert(std::make_pair(bindingID, binding));
+                }
+                else
+                {
+                    if(bindingIter->second.descriptorType != DescriptorType::UNIFORM_BUFFER)
+                        vkcv_log(LogLevel::WARNING, "Descriptor type mismatch in shader reflection!");
+                    // if binding exists, append additional shader stage to it
+                    bindingIter->second.shaderStages | shaderStage;
+                }
+            }
         }
 
         for (uint32_t i = 0; i < resources.storage_buffers.size(); i++) {
             auto& u = resources.storage_buffers[i];
             const spirv_cross::SPIRType& base_type = comp.get_type(u.base_type_id);
-            std::pair descriptor(comp.get_decoration(u.id, spv::DecorationDescriptorSet),
-                DescriptorBinding(comp.get_decoration(u.id, spv::DecorationBinding), DescriptorType::STORAGE_BUFFER, base_type.vecsize, shaderStage));
-            bindings.push_back(descriptor);
-            if ((int32_t)comp.get_decoration(u.id, spv::DecorationDescriptorSet) > maxSetID) 
-                maxSetID = comp.get_decoration(u.id, spv::DecorationDescriptorSet);
+
+            const uint32_t setID = comp.get_decoration(u.id, spv::DecorationDescriptorSet);
+            const uint32_t bindingID = comp.get_decoration(u.id, spv::DecorationBinding);
+
+            const DescriptorBinding binding(bindingID, DescriptorType::STORAGE_BUFFER, base_type.vecsize, shaderStage);
+
+            auto setIter = m_DescriptorSets.find(setID);
+            if (setIter == m_DescriptorSets.end())
+            {
+                // create a map for this set ID
+                std::unordered_map<uint32_t, DescriptorBinding> setBindings;
+                // insert the binding to this set ID's bindings
+                setBindings.insert(std::make_pair(bindingID, binding));
+                // insert this set ID's map to the descriptor sets
+                m_DescriptorSets.insert(std::make_pair(setID, setBindings));
+            }
+            else
+            {
+                // search for an existing binding for this set
+                auto bindingIter = setIter->second.find(bindingID);
+                if (bindingIter == setIter->second.end())
+                {
+                    // if binding did not exist, insert it
+                    setIter->second.insert(std::make_pair(bindingID, binding));
+                }
+                else
+                {
+                    if (bindingIter->second.descriptorType != DescriptorType::STORAGE_BUFFER)
+                        vkcv_log(LogLevel::WARNING, "Descriptor type mismatch in shader reflection!");
+                    // if binding exists, append additional shader stage to it
+                    bindingIter->second.shaderStages | shaderStage;
+                }
+            }
         }
 
         for (uint32_t i = 0; i < resources.separate_samplers.size(); i++) {
             auto& u = resources.separate_samplers[i];
             const spirv_cross::SPIRType& base_type = comp.get_type(u.base_type_id);
-            std::pair descriptor(comp.get_decoration(u.id, spv::DecorationDescriptorSet),
-                DescriptorBinding(comp.get_decoration(u.id, spv::DecorationBinding), DescriptorType::SAMPLER, base_type.vecsize, shaderStage));
-            bindings.push_back(descriptor);
-            if ((int32_t)comp.get_decoration(u.id, spv::DecorationDescriptorSet) > maxSetID) 
-                maxSetID = comp.get_decoration(u.id, spv::DecorationDescriptorSet);
+
+            const uint32_t setID = comp.get_decoration(u.id, spv::DecorationDescriptorSet);
+            const uint32_t bindingID = comp.get_decoration(u.id, spv::DecorationBinding);
+
+            const DescriptorBinding binding(bindingID, DescriptorType::SAMPLER, base_type.vecsize, shaderStage);
+
+            auto setIter = m_DescriptorSets.find(setID);
+            if (setIter == m_DescriptorSets.end())
+            {
+                // create a map for this set ID
+                std::unordered_map<uint32_t, DescriptorBinding> setBindings;
+                // insert the binding to this set ID's bindings
+                setBindings.insert(std::make_pair(bindingID, binding));
+                // insert this set ID's map to the descriptor sets
+                m_DescriptorSets.insert(std::make_pair(setID, setBindings));
+            }
+            else
+            {
+                // search for an existing binding for this set
+                auto bindingIter = setIter->second.find(bindingID);
+                if (bindingIter == setIter->second.end())
+                {
+                    // if binding did not exist, insert it
+                    setIter->second.insert(std::make_pair(bindingID, binding));
+                }
+                else
+                {
+                    if (bindingIter->second.descriptorType != DescriptorType::SAMPLER)
+                        vkcv_log(LogLevel::WARNING, "Descriptor type mismatch in shader reflection!");
+                    // if binding exists, append additional shader stage to it
+                    bindingIter->second.shaderStages | shaderStage;
+                }
+            }
         }
 
         for (uint32_t i = 0; i < resources.separate_images.size(); i++) {
             auto& u = resources.separate_images[i];
             const spirv_cross::SPIRType& base_type = comp.get_type(u.base_type_id);
-            std::pair descriptor(comp.get_decoration(u.id, spv::DecorationDescriptorSet),
-                DescriptorBinding(comp.get_decoration(u.id, spv::DecorationBinding), DescriptorType::IMAGE_SAMPLED, base_type.vecsize, shaderStage));
-            bindings.push_back(descriptor);
-            if ((int32_t)comp.get_decoration(u.id, spv::DecorationDescriptorSet) > maxSetID)
-                maxSetID = comp.get_decoration(u.id, spv::DecorationDescriptorSet);
 
+            const uint32_t setID = comp.get_decoration(u.id, spv::DecorationDescriptorSet);
+            const uint32_t bindingID = comp.get_decoration(u.id, spv::DecorationBinding);
+
+            const DescriptorBinding binding(bindingID, DescriptorType::IMAGE_SAMPLED, base_type.vecsize, shaderStage);
+
+            auto setIter = m_DescriptorSets.find(setID);
+            if (setIter == m_DescriptorSets.end())
+            {
+                // create a map for this set ID
+                std::unordered_map<uint32_t, DescriptorBinding> setBindings;
+                // insert the binding to this set ID's bindings
+                setBindings.insert(std::make_pair(bindingID, binding));
+                // insert this set ID's map to the descriptor sets
+                m_DescriptorSets.insert(std::make_pair(setID, setBindings));
+            }
+            else
+            {
+                // search for an existing binding for this set
+                auto bindingIter = setIter->second.find(bindingID);
+                if (bindingIter == setIter->second.end())
+                {
+                    // if binding did not exist, insert it
+                    setIter->second.insert(std::make_pair(bindingID, binding));
+                }
+                else
+                {
+                    if (bindingIter->second.descriptorType != DescriptorType::IMAGE_SAMPLED)
+                        vkcv_log(LogLevel::WARNING, "Descriptor type mismatch in shader reflection!");
+                    // if binding exists, append additional shader stage to it
+                    bindingIter->second.shaderStages | shaderStage;
+                }
+            }
         }
 
         for (uint32_t i = 0; i < resources.storage_images.size(); i++) {
             auto& u = resources.storage_images[i];
             const spirv_cross::SPIRType& base_type = comp.get_type(u.base_type_id);
-            std::pair descriptor(comp.get_decoration(u.id, spv::DecorationDescriptorSet),
-                DescriptorBinding(comp.get_decoration(u.id, spv::DecorationBinding), DescriptorType::IMAGE_STORAGE, base_type.vecsize, shaderStage));
-            bindings.push_back(descriptor);
-            if ((int32_t)comp.get_decoration(u.id, spv::DecorationDescriptorSet) > maxSetID)
-                maxSetID = comp.get_decoration(u.id, spv::DecorationDescriptorSet);
-        }
-        if (maxSetID != -1) {
-            if((int32_t)m_DescriptorSets.size() <= maxSetID) m_DescriptorSets.resize(maxSetID + 1);
-            for (const auto &binding : bindings) {
-                //checking if descriptor has already been reflected in another shader stage
-                bool bindingFound = false;
-                uint32_t pos = 0;
-                for (const auto& descriptor : m_DescriptorSets[binding.first]) {
-                    if (binding.second.bindingID == descriptor.bindingID) {
-                        if (binding.second.descriptorType == descriptor.descriptorType && binding.second.descriptorCount == descriptor.descriptorCount) {
-                            //updating descriptor binding with another shader stage
-                            ShaderStages updatedShaders = descriptor.shaderStages | shaderStage;
-                            DescriptorBinding newBinding = DescriptorBinding(binding.second.bindingID, binding.second.descriptorType, binding.second.descriptorCount, updatedShaders);
-                            m_DescriptorSets[binding.first][pos] = newBinding;
-                            bindingFound = true;
-                            break;
-                        }
-                        else vkcv_log(LogLevel::ERROR, "Included shaders contain resources with same identifier but different type or count");
-                    }
-                    pos++;
+
+            const uint32_t setID = comp.get_decoration(u.id, spv::DecorationDescriptorSet);
+            const uint32_t bindingID = comp.get_decoration(u.id, spv::DecorationBinding);
+
+            const DescriptorBinding binding(bindingID, DescriptorType::IMAGE_STORAGE, base_type.vecsize, shaderStage);
+
+            auto setIter = m_DescriptorSets.find(setID);
+            if (setIter == m_DescriptorSets.end())
+            {
+                // create a map for this set ID
+                std::unordered_map<uint32_t, DescriptorBinding> setBindings;
+                // insert the binding to this set ID's bindings
+                setBindings.insert(std::make_pair(bindingID, binding));
+                // insert this set ID's map to the descriptor sets
+                m_DescriptorSets.insert(std::make_pair(setID, setBindings));
+            }
+            else
+            {
+                // search for an existing binding for this set
+                auto bindingIter = setIter->second.find(bindingID);
+                if (bindingIter == setIter->second.end())
+                {
+                    // if binding did not exist, insert it
+                    setIter->second.insert(std::make_pair(bindingID, binding));
+                }
+                else
+                {
+                    if (bindingIter->second.descriptorType != DescriptorType::IMAGE_STORAGE)
+                        vkcv_log(LogLevel::WARNING, "Descriptor type mismatch in shader reflection!");
+                    // if binding exists, append additional shader stage to it
+                    bindingIter->second.shaderStages | shaderStage;
                 }
-                //append new descriptor if it has not been reflected yet
-                if(!bindingFound) m_DescriptorSets[binding.first].push_back(binding.second);
             }
         }
 
@@ -231,7 +346,7 @@ namespace vkcv {
         return m_VertexAttachments;
 	}
 
-    const std::vector<std::vector<DescriptorBinding>>& ShaderProgram::getReflectedDescriptors() const {
+    const std::unordered_map<uint32_t, std::unordered_map<uint32_t, DescriptorBinding>>& ShaderProgram::getReflectedDescriptors() const {
         return m_DescriptorSets;
     }