diff --git a/hibernate-core/src/main/java/org/hibernate/boot/beanvalidation/BeanValidationEventListener.java b/hibernate-core/src/main/java/org/hibernate/boot/beanvalidation/BeanValidationEventListener.java
index 2cab523720b2..f3bfee79ca16 100644
--- a/hibernate-core/src/main/java/org/hibernate/boot/beanvalidation/BeanValidationEventListener.java
+++ b/hibernate-core/src/main/java/org/hibernate/boot/beanvalidation/BeanValidationEventListener.java
@@ -55,13 +55,17 @@ public class BeanValidationEventListener
 			BeanValidationEventListener.class.getName()
 	);
 
-	private HibernateTraversableResolver traversableResolver;
-	private Validator validator;
-	private GroupsPerOperation groupsPerOperation;
+	private final HibernateTraversableResolver traversableResolver;
+	private final Validator validator;
+	private final GroupsPerOperation groupsPerOperation;
 
 	public BeanValidationEventListener(
-			ValidatorFactory factory, Map<String, Object> settings, ClassLoaderService classLoaderService) {
-		traversableResolver = new HibernateTraversableResolver();
+			ValidatorFactory factory,
+			Map<String, Object> settings,
+			ClassLoaderService classLoaderService,
+			SessionFactoryImplementor sessionFactory) {
+
+		traversableResolver = new HibernateTraversableResolver( sessionFactory.getPersistenceUnitUtil() );
 		validator = factory.usingContext()
 				.traversableResolver( traversableResolver )
 				.getValidator();
@@ -80,7 +84,6 @@ public boolean onPreInsert(PreInsertEvent event) {
 		validate(
 				event.getEntity(),
 				event.getPersister(),
-				event.getFactory(),
 				GroupsPerOperation.Operation.INSERT
 		);
 		return false;
@@ -90,7 +93,6 @@ public boolean onPreUpdate(PreUpdateEvent event) {
 		validate(
 				event.getEntity(),
 				event.getPersister(),
-				event.getFactory(),
 				GroupsPerOperation.Operation.UPDATE
 		);
 		return false;
@@ -100,7 +102,6 @@ public boolean onPreDelete(PreDeleteEvent event) {
 		validate(
 				event.getEntity(),
 				event.getPersister(),
-				event.getFactory(),
 				GroupsPerOperation.Operation.DELETE
 		);
 		return false;
@@ -111,7 +112,6 @@ public boolean onPreUpsert(PreUpsertEvent event) {
 		validate(
 				event.getEntity(),
 				event.getPersister(),
-				event.getFactory(),
 				GroupsPerOperation.Operation.UPSERT
 		);
 		return false;
@@ -123,7 +123,6 @@ public void onPreUpdateCollection(PreCollectionUpdateEvent event) {
 		validate(
 				entity,
 				event.getSession().getEntityPersister( event.getAffectedOwnerEntityName(), entity ),
-				event.getFactory(),
 				GroupsPerOperation.Operation.UPDATE
 		);
 	}
@@ -131,7 +130,6 @@ public void onPreUpdateCollection(PreCollectionUpdateEvent event) {
 	private <T> void validate(
 			T object,
 			EntityPersister persister,
-			SessionFactoryImplementor sessionFactory,
 			GroupsPerOperation.Operation operation) {
 		if ( object == null || persister.getRepresentationStrategy().getMode() != RepresentationMode.POJO ) {
 			return;
diff --git a/hibernate-core/src/main/java/org/hibernate/boot/beanvalidation/HibernateTraversableResolver.java b/hibernate-core/src/main/java/org/hibernate/boot/beanvalidation/HibernateTraversableResolver.java
index 333819b5d056..299cae47a8c0 100644
--- a/hibernate-core/src/main/java/org/hibernate/boot/beanvalidation/HibernateTraversableResolver.java
+++ b/hibernate-core/src/main/java/org/hibernate/boot/beanvalidation/HibernateTraversableResolver.java
@@ -20,6 +20,7 @@
 import org.hibernate.type.EntityType;
 import org.hibernate.type.Type;
 
+import jakarta.persistence.PersistenceUnitUtil;
 import jakarta.validation.Path;
 import jakarta.validation.TraversableResolver;
 
@@ -32,6 +33,11 @@
  */
 public class HibernateTraversableResolver implements TraversableResolver {
 	private final Map<Class<?>, Set<String>> associationsPerEntityClass = new HashMap<>();
+	private final PersistenceUnitUtil persistenceUnitUtil;
+
+	public HibernateTraversableResolver(PersistenceUnitUtil persistenceUnitUtil) {
+		this.persistenceUnitUtil = persistenceUnitUtil;
+	}
 
 	public void addPersister(EntityPersister persister, SessionFactoryImplementor factory) {
 		Class<?> javaTypeClass = persister.getEntityMappingType().getMappedJavaType().getJavaTypeClass();
@@ -91,7 +97,7 @@ public boolean isReachable(Object traversableObject,
 			ElementType elementType) {
 		//lazy, don't load
 		return Hibernate.isInitialized( traversableObject )
-			&& Hibernate.isPropertyInitialized( traversableObject, traversableProperty.getName() );
+				&& persistenceUnitUtil.isLoaded( traversableObject, traversableProperty.getName() );
 	}
 
 	public boolean isCascadable(Object traversableObject,
diff --git a/hibernate-core/src/main/java/org/hibernate/boot/beanvalidation/TypeSafeActivator.java b/hibernate-core/src/main/java/org/hibernate/boot/beanvalidation/TypeSafeActivator.java
index 9a220f8c7df1..5fd0708dc553 100644
--- a/hibernate-core/src/main/java/org/hibernate/boot/beanvalidation/TypeSafeActivator.java
+++ b/hibernate-core/src/main/java/org/hibernate/boot/beanvalidation/TypeSafeActivator.java
@@ -157,7 +157,12 @@ private static void setupListener(ValidatorFactory validatorFactory, SessionFact
 		final ClassLoaderService classLoaderService = serviceRegistry.requireService( ClassLoaderService.class );
 		final ConfigurationService cfgService = serviceRegistry.requireService( ConfigurationService.class );
 		final BeanValidationEventListener listener =
-				new BeanValidationEventListener( validatorFactory, cfgService.getSettings(), classLoaderService );
+				new BeanValidationEventListener(
+						validatorFactory,
+						cfgService.getSettings(),
+						classLoaderService,
+						sessionFactory
+				);
 		final EventListenerRegistry listenerRegistry = serviceRegistry.requireService( EventListenerRegistry.class );
 		listenerRegistry.addDuplicationStrategy( DuplicationStrategyImpl.INSTANCE );
 		listenerRegistry.appendListeners( EventType.PRE_INSERT, listener );
diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/beanvalidation/LazyPropertiesFetchTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/beanvalidation/LazyPropertiesFetchTest.java
new file mode 100644
index 000000000000..0efe4eabaaeb
--- /dev/null
+++ b/hibernate-core/src/test/java/org/hibernate/orm/test/annotations/beanvalidation/LazyPropertiesFetchTest.java
@@ -0,0 +1,123 @@
+/*
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ * Copyright Red Hat Inc. and Hibernate Authors
+ */
+package org.hibernate.orm.test.annotations.beanvalidation;
+
+import java.util.List;
+
+import org.hibernate.cfg.AvailableSettings;
+
+import org.hibernate.testing.jdbc.SQLStatementInspector;
+import org.hibernate.testing.orm.junit.DomainModel;
+import org.hibernate.testing.orm.junit.JiraKey;
+import org.hibernate.testing.orm.junit.ServiceRegistry;
+import org.hibernate.testing.orm.junit.SessionFactory;
+import org.hibernate.testing.orm.junit.SessionFactoryScope;
+import org.hibernate.testing.orm.junit.Setting;
+import org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.api.Test;
+
+import jakarta.persistence.CascadeType;
+import jakarta.persistence.CollectionTable;
+import jakarta.persistence.ElementCollection;
+import jakarta.persistence.Entity;
+import jakarta.persistence.Id;
+import jakarta.persistence.OneToMany;
+import jakarta.validation.constraints.Size;
+
+@DomainModel(annotatedClasses = {
+		LazyPropertiesFetchTest.Association.class,
+		LazyPropertiesFetchTest.MutableEntity.class
+})
+@ServiceRegistry(settings = @Setting(name = AvailableSettings.JAKARTA_VALIDATION_MODE, value = "CALLBACK"))
+@SessionFactory(useCollectingStatementInspector = true)
+@JiraKey("HHH-19203")
+class LazyPropertiesFetchTest {
+
+	@AfterAll
+	static void cleanup(SessionFactoryScope scope) {
+		scope.dropData();
+	}
+
+	@Test
+	void testLazyCollectionNotFetched(SessionFactoryScope scope) {
+		scope.inTransaction( session -> {
+			MutableEntity mutableEntity = new MutableEntity();
+			mutableEntity.id = 1L;
+			mutableEntity.lazyCollection = List.of( 1, 2 );
+			session.persist( mutableEntity );
+		} );
+
+		SQLStatementInspector inspector = scope.getCollectingStatementInspector();
+		inspector.clear();
+
+		scope.inTransaction( session -> {
+			MutableEntity fetched = session.find( MutableEntity.class, 1L );
+			inspector.assertExecutedCount( 1 );
+			fetched.mutableField = 1;
+		} );
+
+		inspector.assertExecutedCount( 2 );
+	}
+
+	@Test
+	void testLazyCollectionFetchDoesntDependOnEachOther(SessionFactoryScope scope) {
+		scope.inTransaction( session -> {
+			MutableEntity mutableEntity = new MutableEntity();
+			mutableEntity.id = 2L;
+			mutableEntity.lazyCollection = List.of( 1, 2 );
+
+			Association asso = new Association();
+			asso.id = 1L;
+			asso.lazyCollection = List.of( 2, 3 );
+
+			mutableEntity.lazyAssociation = List.of( asso );
+
+			session.persist( mutableEntity );
+		} );
+
+		SQLStatementInspector inspector = scope.getCollectingStatementInspector();
+		inspector.clear();
+
+		scope.inTransaction( session -> {
+			MutableEntity fetched = session.find( MutableEntity.class, 2L );
+			inspector.assertExecutedCount( 1 );
+
+			Association asso = fetched.lazyAssociation.get( 0 );
+			inspector.assertExecutedCount( 2 );
+
+			asso.mutableField = 5;
+		} );
+		inspector.assertExecutedCount( 3 );
+	}
+
+	@Entity(name = "MutableEntity")
+	static class MutableEntity {
+		@Id
+		private Long id;
+
+		private int mutableField = 0;
+
+		@Size(max = 10)
+		@ElementCollection
+		@CollectionTable(name = "LazyPropertiesCollection1")
+		private List<Integer> lazyCollection;
+
+		@OneToMany(cascade = CascadeType.PERSIST)
+		private List<Association> lazyAssociation;
+	}
+
+	@Entity(name = "Association")
+	static class Association {
+		@Id
+		private Long id;
+
+		private int mutableField = 0;
+
+		@Size(max = 10)
+		@ElementCollection
+		@CollectionTable(name = "LazyPropertiesCollection2")
+		private List<Integer> lazyCollection;
+	}
+}