diff --git a/config/Sources.cmake b/config/Sources.cmake
index f0fd0ed758ee8b7f4d8ce0940babf0e1142e6b60..ffbe38d67217ef515c89a5e6a26661441b22491d 100644
--- a/config/Sources.cmake
+++ b/config/Sources.cmake
@@ -30,6 +30,7 @@ set(vkcv_sources
 		${vkcv_include}/vkcv/Buffer.hpp
 		
 		${vkcv_include}/vkcv/PushConstants.hpp
+		${vkcv_source}/vkcv/PushConstants.cpp
 		
 		${vkcv_include}/vkcv/BufferManager.hpp
 		${vkcv_source}/vkcv/BufferManager.cpp
@@ -75,6 +76,9 @@ set(vkcv_sources
 		${vkcv_source}/vkcv/VertexLayout.cpp
 
 		${vkcv_include}/vkcv/Event.hpp
+		
+		${vkcv_include}/vkcv/TypeGuard.hpp
+		${vkcv_source}/vkcv/TypeGuard.cpp
 
 		${vkcv_source}/vkcv/DescriptorManager.hpp
 		${vkcv_source}/vkcv/DescriptorManager.cpp
diff --git a/include/vkcv/PushConstants.hpp b/include/vkcv/PushConstants.hpp
index ca826ea52e9bcee72c14c26496c99937c27fb775..e02e5e6995c9aa563cf24d2e1fe68f879b006a8e 100644
--- a/include/vkcv/PushConstants.hpp
+++ b/include/vkcv/PushConstants.hpp
@@ -9,24 +9,21 @@
 #include <vulkan/vulkan.hpp>
 
 #include "Logger.hpp"
+#include "TypeGuard.hpp"
 
 namespace vkcv {
 
     /**
      * @brief Class to handle push constants data per drawcall.
      */
-	class PushConstants {
+	class PushConstants final {
 	private:
+		TypeGuard m_typeGuard;
 		std::vector<uint8_t> m_data;
-		size_t m_sizePerDrawcall;
 		
 	public:
-		template<typename T>
-		PushConstants() : PushConstants(sizeof(T)) {}
-		
-		explicit PushConstants(size_t sizePerDrawcall) :
-		m_data(),
-		m_sizePerDrawcall(sizePerDrawcall) {}
+		explicit PushConstants(size_t sizePerDrawcall);
+		explicit PushConstants(const TypeGuard &guard);
 		
 		PushConstants(const PushConstants& other) = default;
 		PushConstants(PushConstants&& other) = default;
@@ -43,9 +40,7 @@ namespace vkcv {
 		 * @return Size of data per drawcall
 		 */
 		[[nodiscard]]
-		size_t getSizePerDrawcall() const {
-			return m_sizePerDrawcall;
-		}
+		size_t getSizePerDrawcall() const;
 		
 		/**
 		 * @brief Returns the size of total data stored for
@@ -54,9 +49,7 @@ namespace vkcv {
 		 * @return Total size of data
 		 */
 		[[nodiscard]]
-		size_t getFullSize() const {
-			return m_data.size();
-		}
+		size_t getFullSize() const;
 		
 		/**
 		 * @brief Returns the number of drawcalls that data
@@ -65,17 +58,13 @@ namespace vkcv {
 		 * @return Number of drawcalls
 		 */
 		[[nodiscard]]
-		size_t getDrawcallCount() const {
-			return (m_data.size() / m_sizePerDrawcall);
-		}
+		size_t getDrawcallCount() const;
 		
 		/**
 		 * @brief Clears the data for all drawcalls currently.
 		 * stored.
 		*/
-		void clear() {
-			m_data.clear();
-		}
+		void clear();
 		
 		/**
 		 * @brief Appends data for a single drawcall to the
@@ -87,9 +76,7 @@ namespace vkcv {
 		 */
 		template<typename T = uint8_t>
 		bool appendDrawcall(const T& value) {
-			if (sizeof(T) != m_sizePerDrawcall) {
-				vkcv_log(LogLevel::WARNING, "Size (%lu) of value does not match the specified size per drawcall (%lu)",
-						 sizeof(value), m_sizePerDrawcall);
+			if (!m_typeGuard.template check<T>()) {
 				return false;
 			}
 			
@@ -109,7 +96,7 @@ namespace vkcv {
 		 */
 		template<typename T = uint8_t>
 		T& getDrawcall(size_t index) {
-			const size_t offset = (index * m_sizePerDrawcall);
+			const size_t offset = (index * getSizePerDrawcall());
 			return *reinterpret_cast<T*>(m_data.data() + offset);
 		}
 		
@@ -123,7 +110,7 @@ namespace vkcv {
 		 */
 		template<typename T = uint8_t>
 		const T& getDrawcall(size_t index) const {
-			const size_t offset = (index * m_sizePerDrawcall);
+			const size_t offset = (index * getSizePerDrawcall());
 			return *reinterpret_cast<const T*>(m_data.data() + offset);
 		}
 		
@@ -135,10 +122,7 @@ namespace vkcv {
 		 * @return Drawcall data
 		 */
 		[[nodiscard]]
-		const void* getDrawcallData(size_t index) const {
-			const size_t offset = (index * m_sizePerDrawcall);
-			return reinterpret_cast<const void*>(m_data.data() + offset);
-		}
+		const void* getDrawcallData(size_t index) const;
 		
 		/**
 		 * @brief Returns the pointer to the entire drawcall data which
@@ -147,14 +131,13 @@ namespace vkcv {
 		 * @return Pointer to the data
 		 */
 		[[nodiscard]]
-		const void* getData() const {
-			if (m_data.empty()) {
-				return nullptr;
-			} else {
-				return m_data.data();
-			}
-		}
+		const void* getData() const;
 		
 	};
 	
+	template<typename T>
+	PushConstants pushConstants() {
+		return PushConstants(typeGuard<T>());
+	}
+	
 }
diff --git a/include/vkcv/TypeGuard.hpp b/include/vkcv/TypeGuard.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..64d0f1db09f4e2321d527c832b49464e64099179
--- /dev/null
+++ b/include/vkcv/TypeGuard.hpp
@@ -0,0 +1,78 @@
+#pragma once
+/**
+ * @authors Tobias Frisch
+ * @file vkcv/TypeGuard.hpp
+ * @brief Support type safety for classes in debug compilation.
+ */
+
+#include <stdlib.h>
+#include <typeinfo>
+
+namespace vkcv {
+	
+	class TypeGuard {
+	private:
+#ifndef NDEBUG
+		const char* m_typeName;
+		size_t m_typeHash;
+		
+		[[nodiscard]]
+		bool checkType(const char* name, size_t hash, size_t size) const;
+#endif
+		size_t m_typeSize;
+		
+		[[nodiscard]]
+		bool checkTypeSize(size_t size) const;
+		
+	public:
+		explicit TypeGuard(size_t size = 0);
+		TypeGuard(const std::type_info &info, size_t size);
+		
+		TypeGuard(const TypeGuard &other) = default;
+		TypeGuard(TypeGuard &&other) noexcept;
+		
+		~TypeGuard() = default;
+		
+		TypeGuard& operator=(const TypeGuard &other) = default;
+		TypeGuard& operator=(TypeGuard &&other) noexcept;
+		
+		bool operator==(const TypeGuard &other) const;
+		bool operator!=(const TypeGuard &other) const;
+		
+		template<typename T>
+		[[nodiscard]]
+		bool check() const {
+#ifndef NDEBUG
+			return checkType(typeid(T).name(), typeid(T).hash_code(), sizeof(T));
+#else
+			return checkTypeSize(sizeof(T));
+#endif
+		}
+		
+		[[nodiscard]]
+		size_t typeSize() const;
+		
+	};
+	
+	template<typename T>
+	TypeGuard typeGuard() {
+		static TypeGuard guard (typeid(T), sizeof(T));
+		return guard;
+	}
+	
+	template<typename T>
+	TypeGuard typeGuard(T) {
+		return typeGuard<T>();
+	}
+	
+	template<typename T>
+	TypeGuard typeGuard(const T&) {
+		return typeGuard<T>();
+	}
+	
+	template<typename T>
+	TypeGuard typeGuard(T&&) {
+		return typeGuard<T>();
+	}
+
+}
diff --git a/modules/algorithm/src/vkcv/algorithm/SinglePassDownsampler.cpp b/modules/algorithm/src/vkcv/algorithm/SinglePassDownsampler.cpp
index d022fbed739255bac4fec06136d873c08cae380a..40ac830cd894736b76c5d220118377d02e9bb1b5 100644
--- a/modules/algorithm/src/vkcv/algorithm/SinglePassDownsampler.cpp
+++ b/modules/algorithm/src/vkcv/algorithm/SinglePassDownsampler.cpp
@@ -310,7 +310,10 @@ namespace vkcv::algorithm {
 		dispatch[1] = dispatchThreadGroupCountXY[1];
 		dispatch[2] = m_core.getImageArrayLayers(image);
 		
-		vkcv::PushConstants pushConstants (m_sampler? sizeof(SPDConstantsSampler) : sizeof(SPDConstants));
+		vkcv::PushConstants pushConstants = (m_sampler?
+				vkcv::pushConstants<SPDConstantsSampler>() :
+				vkcv::pushConstants<SPDConstants>()
+		);
 		
 		if (m_sampler) {
 			SPDConstantsSampler data;
diff --git a/modules/effects/src/vkcv/effects/BloomAndFlaresEffect.cpp b/modules/effects/src/vkcv/effects/BloomAndFlaresEffect.cpp
index c8e51fe9716af0304687d6ae60fc0bea2a5d2cc6..d0872f19f52f0e17914c3e760d47b055063636e6 100644
--- a/modules/effects/src/vkcv/effects/BloomAndFlaresEffect.cpp
+++ b/modules/effects/src/vkcv/effects/BloomAndFlaresEffect.cpp
@@ -456,7 +456,7 @@ namespace vkcv::effects {
 		dispatch[1] = calcDispatchSize(sampleHeight, threadGroupWorkRegionDim);
 		dispatch[2] = 1;
 		
-		PushConstants pushConstants (sizeof(m_cameraDirection));
+		PushConstants pushConstants = vkcv::pushConstants<glm::vec3>();
 		pushConstants.appendDrawcall(m_cameraDirection);
 		
 		// bloom composite dispatch
diff --git a/projects/bindless_textures/src/main.cpp b/projects/bindless_textures/src/main.cpp
index 811e1162588fa699b4d74045504dc9c3d4de4f4c..fdef23f8537edeca665a4d4d9994e53af649e989 100644
--- a/projects/bindless_textures/src/main.cpp
+++ b/projects/bindless_textures/src/main.cpp
@@ -256,7 +256,7 @@ int main(int argc, const char** argv) {
 		cameraManager.update(0.000001 * static_cast<double>(deltatime.count()));
         glm::mat4 mvp = cameraManager.getActiveCamera().getMVP();
 
-		vkcv::PushConstants pushConstants (sizeof(glm::mat4));
+		vkcv::PushConstants pushConstants = vkcv::pushConstants<glm::mat4>();
 		pushConstants.appendDrawcall(mvp);
 
 		const std::vector<vkcv::ImageHandle> renderTargets = { swapchainInput, depthBuffer };
diff --git a/projects/first_mesh/src/main.cpp b/projects/first_mesh/src/main.cpp
index fa671a5507a7621586497048128e8959f72cdf08..b84834cda37ef87eb6893ad201a230cbea422d20 100644
--- a/projects/first_mesh/src/main.cpp
+++ b/projects/first_mesh/src/main.cpp
@@ -196,7 +196,7 @@ int main(int argc, const char** argv) {
 		cameraManager.update(0.000001 * static_cast<double>(deltatime.count()));
         glm::mat4 mvp = cameraManager.getActiveCamera().getMVP();
 
-		vkcv::PushConstants pushConstants (sizeof(glm::mat4));
+		vkcv::PushConstants pushConstants = vkcv::pushConstants<glm::mat4>();
 		pushConstants.appendDrawcall(mvp);
 
 		const std::vector<vkcv::ImageHandle> renderTargets = { swapchainInput, depthBuffer };
diff --git a/projects/first_triangle/src/main.cpp b/projects/first_triangle/src/main.cpp
index c2d8bf817dd1d6b2c7cc069f2037ee090abc4415..81330c39c37b24d928e4c34958b8fd3a4dfda10e 100644
--- a/projects/first_triangle/src/main.cpp
+++ b/projects/first_triangle/src/main.cpp
@@ -78,7 +78,6 @@ int main(int argc, const char** argv) {
 	vkcv::DrawcallInfo drawcall(renderMesh, {},1);
 
 	const vkcv::ImageHandle swapchainInput = vkcv::ImageHandle::createSwapchainImageHandle();
-	core.setDebugLabel(swapchainInput, "Swapchain Image");
 
     vkcv::camera::CameraManager cameraManager(window);
     uint32_t camIndex0 = cameraManager.addCamera(vkcv::camera::ControllerType::PILOT);
@@ -104,7 +103,7 @@ int main(int argc, const char** argv) {
 		cameraManager.update(0.000001 * static_cast<double>(deltatime.count()));
         glm::mat4 mvp = cameraManager.getActiveCamera().getMVP();
 
-		vkcv::PushConstants pushConstants (sizeof(glm::mat4));
+		vkcv::PushConstants pushConstants = vkcv::pushConstants<glm::mat4>();
 		pushConstants.appendDrawcall(mvp);
 		
 		auto cmdStream = core.createCommandStream(vkcv::QueueType::Graphics);
diff --git a/projects/indirect_dispatch/src/App.cpp b/projects/indirect_dispatch/src/App.cpp
index e6885b8e7dfa71c00335dbb2cee5c5994ce4eccc..e327ba8200532c022804c90be2b6082aa2b8c65c 100644
--- a/projects/indirect_dispatch/src/App.cpp
+++ b/projects/indirect_dispatch/src/App.cpp
@@ -274,7 +274,7 @@ void App::run() {
 			m_windowHandle);
 
 		// sky
-		vkcv::PushConstants skyPushConstants(sizeof(glm::mat4));
+		vkcv::PushConstants skyPushConstants = vkcv::pushConstants<glm::mat4>();
 		skyPushConstants.appendDrawcall(viewProjection);
 
 		m_core.recordDrawcallsToCmdStream(
diff --git a/projects/indirect_dispatch/src/MotionBlur.cpp b/projects/indirect_dispatch/src/MotionBlur.cpp
index c9345684225e64f792a13ade2e5d11297ab7c444..7f3e8ae8a5deeb55539762554f7b4736331ae499 100644
--- a/projects/indirect_dispatch/src/MotionBlur.cpp
+++ b/projects/indirect_dispatch/src/MotionBlur.cpp
@@ -163,7 +163,7 @@ vkcv::ImageHandle MotionBlur::render(
 	classificationConstants.height              = m_core->getImageHeight(m_renderTargets.outputColor);
 	classificationConstants.fastPathThreshold   = fastPathThreshold;
 
-	vkcv::PushConstants classificationPushConstants(sizeof(ClassificationConstants));
+	vkcv::PushConstants classificationPushConstants = vkcv::pushConstants<ClassificationConstants>();
     classificationPushConstants.appendDrawcall(classificationConstants);
 
 	m_core->prepareImageForSampling(cmdStream, m_renderTargets.motionMaxNeighbourhood);
@@ -235,7 +235,7 @@ vkcv::ImageHandle MotionBlur::render(
 	motionBlurConstantData.cameraFarPlane           = cameraFar;
 	motionBlurConstantData.motionTileOffsetLength   = motionTileOffsetLength;
 
-	vkcv::PushConstants motionBlurPushConstants(sizeof(motionBlurConstantData));
+	vkcv::PushConstants motionBlurPushConstants = vkcv::pushConstants<MotionBlurConstantData>();
 	motionBlurPushConstants.appendDrawcall(motionBlurConstantData);
 
 	struct FastPathConstants {
@@ -244,7 +244,7 @@ vkcv::ImageHandle MotionBlur::render(
 	FastPathConstants fastPathConstants;
 	fastPathConstants.motionFactor = motionBlurConstantData.motionFactor;
 
-	vkcv::PushConstants fastPathPushConstants(sizeof(FastPathConstants));
+	vkcv::PushConstants fastPathPushConstants = vkcv::pushConstants<FastPathConstants>();
 	fastPathPushConstants.appendDrawcall(fastPathConstants);
 
 	m_core->prepareImageForStorage(cmdStream, m_renderTargets.outputColor);
@@ -361,7 +361,7 @@ vkcv::ImageHandle MotionBlur::renderMotionVectorVisualisation(
 	m_core->prepareImageForSampling(cmdStream, visualisationInput);
 	m_core->prepareImageForStorage(cmdStream, m_renderTargets.outputColor);
 
-	vkcv::PushConstants motionVectorVisualisationPushConstants(sizeof(float));
+	vkcv::PushConstants motionVectorVisualisationPushConstants = vkcv::pushConstants<float>();
 	motionVectorVisualisationPushConstants.appendDrawcall(velocityRange);
 
 	const auto dispatchSizes = computeFullscreenDispatchSize(
diff --git a/projects/indirect_draw/src/main.cpp b/projects/indirect_draw/src/main.cpp
index 26f523958e9704d7fc090ceba818591d904a2e92..e9d50c468ad33746b57400edaeb0c36f9d6b38e2 100644
--- a/projects/indirect_draw/src/main.cpp
+++ b/projects/indirect_draw/src/main.cpp
@@ -547,7 +547,7 @@ int main(int argc, const char** argv) {
 		start = end;
 		cameraManager.update(0.000001 * static_cast<double>(deltatime.count()));
         vkcv::camera::Camera cam = cameraManager.getActiveCamera();
-		vkcv::PushConstants pushConstants(sizeof(glm::mat4));
+		vkcv::PushConstants pushConstants = vkcv::pushConstants<glm::mat4>();
 		pushConstants.appendDrawcall(cam.getProjection() * cam.getView());
 
         if(updateFrustumPlanes)
diff --git a/projects/mesh_shader/src/main.cpp b/projects/mesh_shader/src/main.cpp
index a74561ca07f7a052fe71c9e1d1efc751c2ab258c..56a8d827e25c15508717bc8d0dd685156969ed54 100644
--- a/projects/mesh_shader/src/main.cpp
+++ b/projects/mesh_shader/src/main.cpp
@@ -356,7 +356,7 @@ int main(int argc, const char** argv) {
 		const std::vector<vkcv::ImageHandle> renderTargets = { swapchainInput, depthBuffer };
 		auto cmdStream = core.createCommandStream(vkcv::QueueType::Graphics);
 
-		vkcv::PushConstants pushConstantData(sizeof(pushConstants));
+		vkcv::PushConstants pushConstantData = vkcv::pushConstants<PushConstants>();
 		pushConstantData.appendDrawcall(pushConstants);
 
 		if (useMeshShader) {
diff --git a/projects/particle_simulation/src/main.cpp b/projects/particle_simulation/src/main.cpp
index db538796201ee4c1cf5830bfd82036f16a82e693..f13fb8e07addd1c5b6090adb8d43257d47039bc3 100644
--- a/projects/particle_simulation/src/main.cpp
+++ b/projects/particle_simulation/src/main.cpp
@@ -277,7 +277,7 @@ int main(int argc, const char **argv) {
         float random = rdm(rdmEngine);
         glm::vec2 pushData = glm::vec2(deltatime, random);
 
-        vkcv::PushConstants pushConstantsCompute (sizeof(glm::vec2));
+        vkcv::PushConstants pushConstantsCompute = vkcv::pushConstants<glm::vec2>();
         pushConstantsCompute.appendDrawcall(pushData);
         
         uint32_t computeDispatchCount[3] = {static_cast<uint32_t> (std::ceil(particleSystem.getParticles().size()/256.f)),1,1};
diff --git a/projects/path_tracer/src/main.cpp b/projects/path_tracer/src/main.cpp
index 670986fff81d4f308aa063e6275f41872bc8e878..4eb3a6490cb61a791f56e280f4160193caa5e7c6 100644
--- a/projects/path_tracer/src/main.cpp
+++ b/projects/path_tracer/src/main.cpp
@@ -362,7 +362,7 @@ int main(int argc, const char** argv) {
 		raytracingPushData.planeCount   = planes.size();
 		raytracingPushData.frameIndex   = frameIndex;
 
-		vkcv::PushConstants pushConstantsCompute(sizeof(RaytracingPushConstantData));
+		vkcv::PushConstants pushConstantsCompute = vkcv::pushConstants<RaytracingPushConstantData>();
 		pushConstantsCompute.appendDrawcall(raytracingPushData);
 
 		uint32_t traceDispatchCount[3] = { 
diff --git a/projects/rtx_ambient_occlusion/src/main.cpp b/projects/rtx_ambient_occlusion/src/main.cpp
index e1bfd2231bc8047f12ba7d71e6a176f1fd85d92c..4ce5b2b5b023f45a32b96db40f1f8aa2c4006132 100644
--- a/projects/rtx_ambient_occlusion/src/main.cpp
+++ b/projects/rtx_ambient_occlusion/src/main.cpp
@@ -130,7 +130,7 @@ int main(int argc, const char** argv) {
 		raytracingPushData.camera_up = glm::vec4(cameraManager.getActiveCamera().getUp(),0);
 		raytracingPushData.camera_forward = glm::vec4(cameraManager.getActiveCamera().getFront(),0);
 
-		vkcv::PushConstants pushConstantsRTX(sizeof(RaytracingPushConstantData));
+		vkcv::PushConstants pushConstantsRTX = vkcv::pushConstants<RaytracingPushConstantData>();
 		pushConstantsRTX.appendDrawcall(raytracingPushData);
 
 		auto cmdStream = core.createCommandStream(vkcv::QueueType::Graphics);
diff --git a/projects/saf_r/src/main.cpp b/projects/saf_r/src/main.cpp
index 68bc546ded40e7f45454d62bfc4e8cd7227da4b7..b9b290e2d324a8d550a4ffc41e0afe344d90a7db 100644
--- a/projects/saf_r/src/main.cpp
+++ b/projects/saf_r/src/main.cpp
@@ -273,7 +273,7 @@ int main(int argc, const char** argv) {
         raytracingPushData.sphereCount  = spheres.size();
         raytracingPushData.viewToWorld  = glm::inverse(cameraManager.getActiveCamera().getView());
 
-        vkcv::PushConstants pushConstantsCompute(sizeof(RaytracingPushConstantData));
+        vkcv::PushConstants pushConstantsCompute = vkcv::pushConstants<RaytracingPushConstantData>();
         pushConstantsCompute.appendDrawcall(raytracingPushData);
 
 		//dispatch compute shader
diff --git a/projects/voxelization/src/ShadowMapping.cpp b/projects/voxelization/src/ShadowMapping.cpp
index a4b967b33f47110df42ca02849fbeb06b4a024f8..8b8fd8bd87f5349372233111c06917075406ffb7 100644
--- a/projects/voxelization/src/ShadowMapping.cpp
+++ b/projects/voxelization/src/ShadowMapping.cpp
@@ -255,7 +255,7 @@ void ShadowMapping::recordShadowMapRendering(
 		voxelVolumeExtent);
 	m_lightInfoBuffer.fill({ lightInfo });
 	
-	vkcv::PushConstants shadowPushConstants (sizeof(glm::mat4));
+	vkcv::PushConstants shadowPushConstants = vkcv::pushConstants<glm::mat4>();
 	
 	for (const auto& m : modelMatrices) {
 		shadowPushConstants.appendDrawcall(lightInfo.lightMatrix * m);
@@ -286,7 +286,7 @@ void ShadowMapping::recordShadowMapRendering(
 
 	const uint32_t msaaSampleCount = msaaToSampleCount(msaa);
 	
-	vkcv::PushConstants msaaPushConstants (sizeof(msaaSampleCount));
+	vkcv::PushConstants msaaPushConstants = vkcv::pushConstants<uint32_t>();
 	msaaPushConstants.appendDrawcall(msaaSampleCount);
 
 	m_corePtr->recordBeginDebugLabel(cmdStream, "Depth to moments", { 1, 1, 1, 1 });
diff --git a/projects/voxelization/src/Voxelization.cpp b/projects/voxelization/src/Voxelization.cpp
index b30d8a7fa1e9cb56158903de4b11c24ddc503b94..99e82ce7520fb54b3bbfcc625467261bef1bf741 100644
--- a/projects/voxelization/src/Voxelization.cpp
+++ b/projects/voxelization/src/Voxelization.cpp
@@ -259,7 +259,7 @@ void Voxelization::voxelizeMeshes(
 	resetVoxelDispatchCount[1] = 1;
 	resetVoxelDispatchCount[2] = 1;
 	
-	vkcv::PushConstants voxelCountPushConstants (sizeof(voxelCount));
+	vkcv::PushConstants voxelCountPushConstants = vkcv::pushConstants<uint32_t>();
 	voxelCountPushConstants.appendDrawcall(voxelCount);
 
 	m_corePtr->recordBeginDebugLabel(cmdStream, "Voxel reset", { 1, 1, 1, 1 });
@@ -343,7 +343,7 @@ void Voxelization::renderVoxelVisualisation(
 	uint32_t                                mipLevel,
 	const vkcv::WindowHandle&               windowHandle) {
 
-	vkcv::PushConstants voxelVisualisationPushConstants (sizeof(glm::mat4));
+	vkcv::PushConstants voxelVisualisationPushConstants = vkcv::pushConstants<glm::mat4>();
 	voxelVisualisationPushConstants.appendDrawcall(viewProjectin);
 
 	mipLevel = std::clamp(mipLevel, (uint32_t)0, m_voxelImage.getMipCount()-1);
diff --git a/projects/voxelization/src/main.cpp b/projects/voxelization/src/main.cpp
index fe096114ead0b66a6d919a4d49baa791debc4897..b2101b1dc436d66c441c0a453a7498577578c9d3 100644
--- a/projects/voxelization/src/main.cpp
+++ b/projects/voxelization/src/main.cpp
@@ -259,7 +259,6 @@ int main(int argc, const char** argv) {
 	std::vector<vkcv::Image> sceneImages;
 	
 	vkcv::algorithm::SinglePassDownsampler spdDownsampler (core, colorSampler);
-	vkcv::Downsampler &downsampler = core.getDownsampler();
 	
 	auto mipStream = core.createCommandStream(vkcv::QueueType::Graphics);
 
@@ -800,7 +799,7 @@ int main(int argc, const char** argv) {
 		// depth prepass
 		const glm::mat4 viewProjectionCamera = cameraManager.getActiveCamera().getMVP();
 		
-		vkcv::PushConstants prepassPushConstants (sizeof(glm::mat4));
+		vkcv::PushConstants prepassPushConstants = vkcv::pushConstants<glm::mat4>();
 		
 		std::vector<glm::mat4> prepassMatrices;
 		for (const auto& m : modelMatrices) {
@@ -853,7 +852,7 @@ int main(int argc, const char** argv) {
 			voxelization.renderVoxelVisualisation(cmdStream, viewProjectionCamera, renderTargets, voxelVisualisationMip, windowHandle);
 		}
 		
-		vkcv::PushConstants skySettingsPushConstants (sizeof(skySettings));
+		vkcv::PushConstants skySettingsPushConstants = vkcv::pushConstants<SkySettings>();
 		skySettingsPushConstants.appendDrawcall(skySettings);
 
 		// sky
@@ -943,7 +942,7 @@ int main(int argc, const char** argv) {
 		auto timeSinceStart = std::chrono::duration_cast<std::chrono::microseconds>(end - appStartTime);
 		float timeF         = static_cast<float>(timeSinceStart.count()) * 0.01f;
 		
-		vkcv::PushConstants timePushConstants (sizeof(timeF));
+		vkcv::PushConstants timePushConstants = vkcv::pushConstants<float>();
 		timePushConstants.appendDrawcall(timeF);
 		
 		fulsscreenDispatchCount[0] = static_cast<uint32_t>(
diff --git a/projects/wobble_bobble/src/main.cpp b/projects/wobble_bobble/src/main.cpp
index 7c865fac55cc9c4a7185006b3b74b205f9ac9105..4cbca35f10ed9f88f25051bb7bc9b8e4d71c235b 100644
--- a/projects/wobble_bobble/src/main.cpp
+++ b/projects/wobble_bobble/src/main.cpp
@@ -684,13 +684,13 @@ int main(int argc, const char **argv) {
 		physics.dt = static_cast<float>(0.000001 * static_cast<double>(deltatime.count()));
 		physics.speedfactor = speed_factor;
 		
-		vkcv::PushConstants physicsPushConstants(sizeof(physics));
+		vkcv::PushConstants physicsPushConstants = vkcv::pushConstants<Physics>();
 		physicsPushConstants.appendDrawcall(physics);
 		
 		cameraManager.update(physics.dt);
 		
 		glm::mat4 mvp = cameraManager.getActiveCamera().getMVP();
-		vkcv::PushConstants cameraPushConstants(sizeof(glm::mat4));
+		vkcv::PushConstants cameraPushConstants = vkcv::pushConstants<glm::mat4>();
 		cameraPushConstants.appendDrawcall(mvp);
 		
 		auto cmdStream = core.createCommandStream(vkcv::QueueType::Graphics);
diff --git a/src/vkcv/PushConstants.cpp b/src/vkcv/PushConstants.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..5492ba2e93df1eeceaf70a8dcca4841f6243cc43
--- /dev/null
+++ b/src/vkcv/PushConstants.cpp
@@ -0,0 +1,44 @@
+#include <vkcv/PushConstants.hpp>
+
+namespace vkcv {
+	
+	PushConstants::PushConstants(size_t sizePerDrawcall) :
+	m_typeGuard(sizePerDrawcall),
+	m_data()
+	{}
+	
+	PushConstants::PushConstants(const TypeGuard &guard) :
+	m_typeGuard(guard),
+	m_data()
+	{}
+	
+	size_t PushConstants::getSizePerDrawcall() const {
+		return m_typeGuard.typeSize();
+	}
+	
+	size_t PushConstants::getFullSize() const {
+		return m_data.size();
+	}
+	
+	size_t PushConstants::getDrawcallCount() const {
+		return getFullSize() / getSizePerDrawcall();
+	}
+	
+	void PushConstants::clear() {
+		m_data.clear();
+	}
+
+	const void* PushConstants::getDrawcallData(size_t index) const {
+		const size_t offset = (index * getSizePerDrawcall());
+		return reinterpret_cast<const void*>(m_data.data() + offset);
+	}
+
+	const void* PushConstants::getData() const {
+		if (m_data.empty()) {
+			return nullptr;
+		} else {
+			return m_data.data();
+		}
+	}
+
+}
diff --git a/src/vkcv/TypeGuard.cpp b/src/vkcv/TypeGuard.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..06e566a13f287051db8fbe55a20a06bfa3e559c2
--- /dev/null
+++ b/src/vkcv/TypeGuard.cpp
@@ -0,0 +1,109 @@
+#include <vkcv/TypeGuard.hpp>
+
+#include <vkcv/Logger.hpp>
+#include <string.h>
+
+namespace vkcv {
+	
+#ifndef NDEBUG
+	bool TypeGuard::checkType(const char* name, size_t hash, size_t size) const {
+		if (!checkTypeSize(size)) {
+			return false;
+		}
+		
+		if ((!m_typeName) || (!name)) {
+			return true;
+		}
+		
+		if (m_typeHash != hash) {
+			vkcv_log(
+					LogLevel::WARNING,
+					"Hash (%lu) does not match the specified hash of the type guard (%lu)",
+					hash,
+					m_typeHash
+			);
+			
+			return false;
+		}
+		
+		if (strcmp(m_typeName, name) != 0) {
+			vkcv_log(
+					LogLevel::WARNING,
+					"Name (%s) does not match the specified name of the type guard (%s)",
+					name,
+					m_typeName
+			);
+			
+			return false;
+		} else {
+			return true;
+		}
+	}
+#endif
+	
+	bool TypeGuard::checkTypeSize(size_t size) const {
+		if (m_typeSize != size) {
+			vkcv_log(
+					LogLevel::WARNING,
+					"Size (%lu) does not match the specified size of the type guard (%lu)",
+					size,
+					m_typeSize
+			);
+			
+			return false;
+		} else {
+			return true;
+		}
+	}
+	
+	TypeGuard::TypeGuard(size_t size) :
+#ifndef NDEBUG
+	m_typeName(nullptr), m_typeHash(0),
+#endif
+	m_typeSize(size)
+	{}
+	
+	TypeGuard::TypeGuard(const std::type_info &info, size_t size) :
+#ifndef NDEBUG
+	m_typeName(info.name()), m_typeHash(info.hash_code()),
+#endif
+	m_typeSize(size)
+	{}
+	
+	TypeGuard::TypeGuard(TypeGuard &&other) noexcept :
+#ifndef NDEBUG
+	m_typeName(other.m_typeName), m_typeHash(other.m_typeHash),
+#endif
+	m_typeSize(other.m_typeSize)
+	{}
+	
+	TypeGuard& TypeGuard::operator=(TypeGuard &&other) noexcept {
+#ifndef NDEBUG
+		m_typeName = other.m_typeName;
+		m_typeHash = other.m_typeHash;
+#endif
+		m_typeSize = other.m_typeSize;
+		return *this;
+	}
+
+	bool TypeGuard::operator==(const TypeGuard &other) const {
+#ifndef NDEBUG
+		return checkType(other.m_typeName, other.m_typeHash, other.m_typeSize);
+#else
+		return checkTypeSize(other.m_typeSize);
+#endif
+	}
+
+	bool TypeGuard::operator!=(const TypeGuard &other) const {
+#ifndef NDEBUG
+		return !checkType(other.m_typeName, other.m_typeHash, other.m_typeSize);
+#else
+		return !checkTypeSize(other.m_typeSize);
+#endif
+	}
+
+	size_t TypeGuard::typeSize() const {
+		return m_typeSize;
+	}
+
+}