diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/sql/BaseSqmToSqlAstConverter.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/sql/BaseSqmToSqlAstConverter.java
index 46e050d7e66e..d03270260705 100644
--- a/hibernate-core/src/main/java/org/hibernate/query/sqm/sql/BaseSqmToSqlAstConverter.java
+++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/sql/BaseSqmToSqlAstConverter.java
@@ -8366,6 +8366,15 @@ else if ( getLoadQueryInfluencers().hasEnabledFetchProfiles() ) {
}
else {
tableGroup = compatibleTableGroup;
+
+ if ( joinProducer instanceof PluralAttributeMapping attributeMapping ) {
+ if ( attributeMapping.getOrderByFragment() != null ) {
+ applyOrdering( tableGroup, attributeMapping.getOrderByFragment() );
+ }
+ if ( attributeMapping.getManyToManyOrderByFragment() != null ) {
+ applyOrdering( tableGroup, attributeMapping.getManyToManyOrderByFragment() );
+ }
+ }
}
// and return the joined group
diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/entitygraph/FetchGraphCollectionOrderByAndCriteriaJoinTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/entitygraph/FetchGraphCollectionOrderByAndCriteriaJoinTest.java
new file mode 100644
index 000000000000..6975a030612f
--- /dev/null
+++ b/hibernate-core/src/test/java/org/hibernate/orm/test/entitygraph/FetchGraphCollectionOrderByAndCriteriaJoinTest.java
@@ -0,0 +1,327 @@
+package org.hibernate.orm.test.entitygraph;
+
+import jakarta.persistence.CascadeType;
+import jakarta.persistence.Entity;
+import jakarta.persistence.FetchType;
+import jakarta.persistence.Id;
+import jakarta.persistence.JoinColumn;
+import jakarta.persistence.ManyToOne;
+import jakarta.persistence.NamedAttributeNode;
+import jakarta.persistence.NamedEntityGraph;
+import jakarta.persistence.NamedEntityGraphs;
+import jakarta.persistence.NamedSubgraph;
+import jakarta.persistence.OneToMany;
+import jakarta.persistence.OrderBy;
+import jakarta.persistence.criteria.JoinType;
+import jakarta.persistence.criteria.Predicate;
+import org.hibernate.Hibernate;
+import org.hibernate.graph.spi.RootGraphImplementor;
+import org.hibernate.query.Query;
+import org.hibernate.query.criteria.HibernateCriteriaBuilder;
+import org.hibernate.query.criteria.JpaCriteriaQuery;
+import org.hibernate.query.criteria.JpaJoin;
+import org.hibernate.query.criteria.JpaRoot;
+import org.hibernate.testing.orm.junit.DomainModel;
+import org.hibernate.testing.orm.junit.Jira;
+import org.hibernate.testing.orm.junit.SessionFactory;
+import org.hibernate.testing.orm.junit.SessionFactoryScope;
+import org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Random;
+import java.util.Set;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+/**
+ * @author baranyit@gmail.com
+ */
+@DomainModel(annotatedClasses = {
+ FetchGraphCollectionOrderByAndCriteriaJoinTest.Level1.class,
+ FetchGraphCollectionOrderByAndCriteriaJoinTest.Level2.class,
+ FetchGraphCollectionOrderByAndCriteriaJoinTest.Level3.class,
+})
+@SessionFactory
+@Jira( "https://hibernate.atlassian.net/browse/HHH-19207" )
+public class FetchGraphCollectionOrderByAndCriteriaJoinTest {
+
+ @Test
+ public void testJoinAndFilter(SessionFactoryScope scope) {
+ executeTest( scope, true, true );
+ }
+
+ @Test
+ public void testNotJoinAndNotFilter(SessionFactoryScope scope) {
+ executeTest( scope, false, false );
+ }
+
+ /**
+ * This case describes the problem of using a fetch graph with a collection that has an @OrderBy clause
+ * and a criteria join without any usage.
+ *
+ * This test case is expected to fail because the @OrderBy is not applied to the collection in the
+ * generated SQL query.
+ *
+ * The issue can also be solved by optimizing the criteria definition like in the test case
+ * testJoinAndFilter or testNotJoinAndNotFilter, but there are some program code
+ * structures where it is not possible to do it, or makes the source code more complex and less readable.
+ *
+ * The required and the logical behaviour should be that the @OrderBy clause is applied to the
+ * collection as in the other test cases. If this problem occurs very difficult to find out the reason because
+ * this behaviour is not documented and the source code looks correct.
+ */
+ @Test
+ public void testJoinAndNotFilter(SessionFactoryScope scope) {
+ executeTest( scope, true, false );
+ }
+
+
+ private void executeTest(SessionFactoryScope scope, boolean directJoin, boolean filterOnJoin) {
+ scope.inTransaction( session -> {
+ HibernateCriteriaBuilder builder = session.getCriteriaBuilder();
+ JpaCriteriaQuery criteriaQuery = builder.createQuery( Level1.class );
+ JpaRoot root = criteriaQuery.from( Level1.class );
+
+ List predicates = new ArrayList<>();
+ predicates.add(
+ builder.equal( root.get( "id" ), 1L )
+ );
+
+ if ( directJoin || filterOnJoin ) {
+ // Directly add the join to the level2 and level3 entities
+ JpaJoin