diff --git a/runtime/interpreter/value_range.go b/runtime/interpreter/value_range.go
index 41a8859adc..0683ed6f32 100644
--- a/runtime/interpreter/value_range.go
+++ b/runtime/interpreter/value_range.go
@@ -40,9 +40,15 @@ func NewInclusiveRangeValue(
 		panic(errors.NewUnreachableError())
 	}
 
-	step := getValueForIntegerType(1, rangeType.ElementType)
+	step := GetValueForIntegerType(1, rangeType.ElementType)
 	if startComparable.Greater(interpreter, endInclusiveComparable, locationRange) {
-		// TODO: Disallow unsigned integers to have a negative step.
+		elemSemaTy := interpreter.MustConvertStaticToSemaType(rangeType.ElementType)
+		if _, ok := sema.AllUnsignedIntegerTypesSet[elemSemaTy]; ok {
+			panic(InclusiveRangeConstructionError{
+				LocationRange: locationRange,
+				Message:       fmt.Sprintf("step value cannot be negative for unsigned integer type %s", elemSemaTy),
+			})
+		}
 
 		negatedStep, ok := step.Negate(interpreter, locationRange).(IntegerValue)
 		if !ok {
@@ -65,10 +71,8 @@ func NewInclusiveRangeValueWithStep(
 	rangeType InclusiveRangeStaticType,
 ) *CompositeValue {
 
-	// TODO: Validate that if start > end, then the type is signed integer.
-
 	// Validate that the step is non-zero.
-	if step.Equal(interpreter, locationRange, getValueForIntegerType(0, rangeType.ElementType)) {
+	if step.Equal(interpreter, locationRange, GetValueForIntegerType(0, rangeType.ElementType)) {
 		panic(InclusiveRangeConstructionError{
 			LocationRange: locationRange,
 			Message:       "step value cannot be zero",
@@ -79,8 +83,8 @@ func NewInclusiveRangeValueWithStep(
 	// If start < end, step must be > 0
 	// If start > end, step must be < 0
 	// If start == end, step doesn't matter.
-	if (start.Less(interpreter, end, locationRange) && step.Less(interpreter, getValueForIntegerType(0, rangeType.ElementType), locationRange)) ||
-		(start.Greater(interpreter, end, locationRange) && step.Greater(interpreter, getValueForIntegerType(0, rangeType.ElementType), locationRange)) {
+	if (start.Less(interpreter, end, locationRange) && step.Less(interpreter, GetValueForIntegerType(0, rangeType.ElementType), locationRange)) ||
+		(start.Greater(interpreter, end, locationRange) && step.Greater(interpreter, GetValueForIntegerType(0, rangeType.ElementType), locationRange)) {
 
 		panic(InclusiveRangeConstructionError{
 			LocationRange: locationRange,
@@ -173,7 +177,7 @@ func rangeContains(
 				panic(errors.NewUnreachableError())
 			}
 
-			result = diff.Mod(interpreter, step, locationRange).Equal(interpreter, locationRange, getValueForIntegerType(0, rangeType.ElementType))
+			result = diff.Mod(interpreter, step, locationRange).Equal(interpreter, locationRange, GetValueForIntegerType(0, rangeType.ElementType))
 		}
 	}
 
@@ -182,7 +186,7 @@ func rangeContains(
 
 // Get the provided int64 value in the required staticType.
 // Note: Assumes that the provided value fits within the constraints of the staticType.
-func getValueForIntegerType(value int64, staticType StaticType) IntegerValue {
+func GetValueForIntegerType(value int64, staticType StaticType) IntegerValue {
 	switch staticType {
 	case PrimitiveStaticTypeInt:
 		return NewUnmeteredIntValueFromInt64(value)
@@ -242,7 +246,7 @@ func getFieldAsIntegerValue(
 		rangeValue.GetField(
 			interpreter,
 			locationRange,
-			sema.InclusiveRangeTypeStartFieldName,
+			name,
 		),
 	)
 }
diff --git a/runtime/sema/type.go b/runtime/sema/type.go
index c4cf834680..9520ae3ab9 100644
--- a/runtime/sema/type.go
+++ b/runtime/sema/type.go
@@ -3239,6 +3239,8 @@ var AllUnsignedIntegerTypes = []Type{
 	Word256Type,
 }
 
+var AllUnsignedIntegerTypesSet = make(map[Type]struct{})
+
 var AllIntegerTypes = append(
 	append(
 		AllUnsignedIntegerTypes[:],
@@ -3386,6 +3388,11 @@ func init() {
 			)
 		}
 	}
+
+	// Populate AllUnsignedIntegerTypesSet
+	for _, ty := range AllUnsignedIntegerTypes {
+		AllUnsignedIntegerTypesSet[ty] = struct{}{}
+	}
 }
 
 func NumberConversionFunctionType(numberType Type) *FunctionType {
diff --git a/runtime/tests/checker/range_value_test.go b/runtime/tests/checker/range_value_test.go
index 8adfd7135f..7f5be159da 100644
--- a/runtime/tests/checker/range_value_test.go
+++ b/runtime/tests/checker/range_value_test.go
@@ -277,14 +277,14 @@ func TestInclusiveRangeConstructionValid(t *testing.T) {
 }
 
 func TestInclusiveRangeConstructionInvalid(t *testing.T) {
-	// t.Parallel()
+	t.Parallel()
 
 	baseValueActivation := sema.NewVariableActivation(sema.BaseValueActivation)
 	baseValueActivation.DeclareValue(stdlib.InclusiveRangeConstructorFunction)
 
 	runInvalidCase := func(t *testing.T, label, code string, expectedErrorTypes []interface{}) {
 		t.Run(label, func(t *testing.T) {
-			// t.Parallel()
+			t.Parallel()
 
 			_, err := ParseAndCheckWithOptions(t, code,
 				ParseAndCheckOptions{
diff --git a/runtime/tests/interpreter/range_value_test.go b/runtime/tests/interpreter/range_value_test.go
index 4d873d1457..cb17855eec 100644
--- a/runtime/tests/interpreter/range_value_test.go
+++ b/runtime/tests/interpreter/range_value_test.go
@@ -20,6 +20,7 @@ package interpreter_test
 
 import (
 	"fmt"
+	"strings"
 	"testing"
 
 	"github.com/stretchr/testify/require"
@@ -28,8 +29,22 @@ import (
 	"github.com/onflow/cadence/runtime/interpreter"
 	"github.com/onflow/cadence/runtime/sema"
 	"github.com/onflow/cadence/runtime/stdlib"
+	"github.com/onflow/cadence/runtime/tests/utils"
+	. "github.com/onflow/cadence/runtime/tests/utils"
 )
 
+type containsTestCase struct {
+	param               int64
+	expectedWithoutStep bool
+	expectedWithStep    bool
+}
+
+type inclusiveRangeConstructionTest struct {
+	ty            sema.Type
+	s, e, step    int64
+	containsTests []containsTestCase
+}
+
 func TestInclusiveRange(t *testing.T) {
 	t.Parallel()
 
@@ -39,39 +54,343 @@ func TestInclusiveRange(t *testing.T) {
 	baseActivation := activations.NewActivation(nil, interpreter.BaseActivation)
 	interpreter.Declare(baseActivation, stdlib.InclusiveRangeConstructorFunction)
 
-	runValidCase := func(t *testing.T, memberType sema.Type, withStep bool) {
-		t.Run(memberType.String(), func(t *testing.T) {
+	unsignedContainsTestCases := []containsTestCase{
+		{
+			param:               1,
+			expectedWithoutStep: true,
+			expectedWithStep:    false,
+		},
+		{
+			param:               12,
+			expectedWithoutStep: false,
+			expectedWithStep:    false,
+		},
+		{
+			param:               10,
+			expectedWithoutStep: true,
+			expectedWithStep:    true,
+		},
+		{
+			param:               0,
+			expectedWithoutStep: true,
+			expectedWithStep:    true,
+		},
+		{
+			param:               2,
+			expectedWithoutStep: true,
+			expectedWithStep:    true,
+		},
+	}
+
+	signedContainsTestCasesForward := []containsTestCase{
+		{
+			param:               1,
+			expectedWithoutStep: true,
+			expectedWithStep:    false,
+		},
+		{
+			param:               100,
+			expectedWithoutStep: false,
+			expectedWithStep:    false,
+		},
+		{
+			param:               -100,
+			expectedWithoutStep: false,
+			expectedWithStep:    false,
+		},
+		{
+			param:               0,
+			expectedWithoutStep: true,
+			expectedWithStep:    true,
+		},
+		{
+			param:               4,
+			expectedWithoutStep: true,
+			expectedWithStep:    true,
+		},
+		{
+			param:               10,
+			expectedWithoutStep: true,
+			expectedWithStep:    true,
+		},
+	}
+	signedContainsTestCasesBackward := []containsTestCase{
+		{
+			param:               1,
+			expectedWithoutStep: true,
+			expectedWithStep:    false,
+		},
+		{
+			param:               12,
+			expectedWithoutStep: false,
+			expectedWithStep:    false,
+		},
+		{
+			param:               -12,
+			expectedWithoutStep: false,
+			expectedWithStep:    false,
+		},
+		{
+			param:               10,
+			expectedWithoutStep: true,
+			expectedWithStep:    true,
+		},
+		{
+			param:               -10,
+			expectedWithoutStep: true,
+			expectedWithStep:    true,
+		},
+		{
+			param:               -8,
+			expectedWithoutStep: true,
+			expectedWithStep:    true,
+		},
+	}
+
+	validTestCases := []inclusiveRangeConstructionTest{
+		// Int*
+		{
+			ty:            sema.IntType,
+			s:             0,
+			e:             10,
+			step:          2,
+			containsTests: signedContainsTestCasesForward,
+		},
+		{
+			ty:            sema.IntType,
+			s:             10,
+			e:             -10,
+			step:          -2,
+			containsTests: signedContainsTestCasesBackward,
+		},
+		{
+			ty:            sema.Int8Type,
+			s:             0,
+			e:             10,
+			step:          2,
+			containsTests: signedContainsTestCasesForward,
+		},
+		{
+			ty:            sema.Int8Type,
+			s:             10,
+			e:             -10,
+			step:          -2,
+			containsTests: signedContainsTestCasesBackward,
+		},
+		{
+			ty:            sema.Int16Type,
+			s:             0,
+			e:             10,
+			step:          2,
+			containsTests: signedContainsTestCasesForward,
+		},
+		{
+			ty:            sema.Int16Type,
+			s:             10,
+			e:             -10,
+			step:          -2,
+			containsTests: signedContainsTestCasesBackward,
+		},
+		{
+			ty:            sema.Int32Type,
+			s:             0,
+			e:             10,
+			step:          2,
+			containsTests: signedContainsTestCasesForward,
+		},
+		{
+			ty:            sema.Int32Type,
+			s:             10,
+			e:             -10,
+			step:          -2,
+			containsTests: signedContainsTestCasesBackward,
+		},
+		{
+			ty:            sema.Int64Type,
+			s:             0,
+			e:             10,
+			step:          2,
+			containsTests: signedContainsTestCasesForward,
+		},
+		{
+			ty:            sema.Int64Type,
+			s:             10,
+			e:             -10,
+			step:          -2,
+			containsTests: signedContainsTestCasesBackward,
+		},
+		{
+			ty:            sema.Int128Type,
+			s:             0,
+			e:             10,
+			step:          2,
+			containsTests: signedContainsTestCasesForward,
+		},
+		{
+			ty:            sema.Int128Type,
+			s:             10,
+			e:             -10,
+			step:          -2,
+			containsTests: signedContainsTestCasesBackward,
+		},
+		{
+			ty:            sema.Int256Type,
+			s:             0,
+			e:             10,
+			step:          2,
+			containsTests: signedContainsTestCasesForward,
+		},
+		{
+			ty:            sema.Int256Type,
+			s:             10,
+			e:             -10,
+			step:          -2,
+			containsTests: signedContainsTestCasesBackward,
+		},
+
+		// UInt*
+		{
+			ty:            sema.UIntType,
+			s:             0,
+			e:             10,
+			step:          2,
+			containsTests: unsignedContainsTestCases,
+		},
+		{
+			ty:            sema.UInt8Type,
+			s:             0,
+			e:             10,
+			step:          2,
+			containsTests: unsignedContainsTestCases,
+		},
+		{
+			ty:            sema.UInt16Type,
+			s:             0,
+			e:             10,
+			step:          2,
+			containsTests: unsignedContainsTestCases,
+		},
+		{
+			ty:            sema.UInt32Type,
+			s:             0,
+			e:             10,
+			step:          2,
+			containsTests: unsignedContainsTestCases,
+		},
+		{
+			ty:            sema.UInt64Type,
+			s:             0,
+			e:             10,
+			step:          2,
+			containsTests: unsignedContainsTestCases,
+		},
+		{
+			ty:            sema.UInt128Type,
+			s:             0,
+			e:             10,
+			step:          2,
+			containsTests: unsignedContainsTestCases,
+		},
+		{
+			ty:            sema.UInt256Type,
+			s:             0,
+			e:             10,
+			step:          2,
+			containsTests: unsignedContainsTestCases,
+		},
+
+		// Word*
+		{
+			ty:            sema.Word8Type,
+			s:             0,
+			e:             10,
+			step:          2,
+			containsTests: unsignedContainsTestCases,
+		},
+		{
+			ty:            sema.Word16Type,
+			s:             0,
+			e:             10,
+			step:          2,
+			containsTests: unsignedContainsTestCases,
+		},
+		{
+			ty:            sema.Word32Type,
+			s:             0,
+			e:             10,
+			step:          2,
+			containsTests: unsignedContainsTestCases,
+		},
+		{
+			ty:            sema.Word64Type,
+			s:             0,
+			e:             10,
+			step:          2,
+			containsTests: unsignedContainsTestCases,
+		},
+		{
+			ty:            sema.Word128Type,
+			s:             0,
+			e:             10,
+			step:          2,
+			containsTests: unsignedContainsTestCases,
+		},
+		{
+			ty:            sema.Word256Type,
+			s:             0,
+			e:             10,
+			step:          2,
+			containsTests: unsignedContainsTestCases,
+		},
+	}
+
+	runValidCase := func(t *testing.T, testCase inclusiveRangeConstructionTest, withStep bool) {
+		t.Run(testCase.ty.String(), func(t *testing.T) {
 			t.Parallel()
 
+			// Generate code for the contains calls.
+			var containsCode string
+			for i, tc := range testCase.containsTests {
+				containsCode += fmt.Sprintf("\nlet c_%d = r.contains(%d)", i, tc.param)
+			}
+
 			var code string
 			if withStep {
 				code = fmt.Sprintf(
 					`
-					   let s : %s = 10
-					   let e : %s = 20
-					   let step : %s = 2
+					   let s : %s = %d
+					   let e : %s = %d
+					   let step : %s = %d
 					   let r = InclusiveRange(s, e, step: step)
 
-					   let count = r.count
-					   
-					   let containsTest = r.contains(s)
+					   %s
 					`,
-					memberType.String(), memberType.String(), memberType.String())
+					testCase.ty.String(),
+					testCase.s,
+					testCase.ty.String(),
+					testCase.e,
+					testCase.ty.String(),
+					testCase.step,
+					containsCode,
+				)
 			} else {
 				code = fmt.Sprintf(
 					`
-					   let s : %s = 10
-					   let e : %s = 20
+					   let s : %s = %d
+					   let e : %s = %d
 					   let r = InclusiveRange(s, e)
 
-					   let count = r.count
-
-					   let containsTest = r.contains(s)
+					   %s
 					`,
-					memberType.String(), memberType.String())
+					testCase.ty.String(),
+					testCase.s,
+					testCase.ty.String(),
+					testCase.e,
+					containsCode,
+				)
 			}
 
-			_, err := parseCheckAndInterpretWithOptions(t, code,
+			inter, err := parseCheckAndInterpretWithOptions(t, code,
 				ParseCheckAndInterpretOptions{
 					CheckerConfig: &sema.Config{
 						BaseValueActivation: baseValueActivation,
@@ -83,23 +402,164 @@ func TestInclusiveRange(t *testing.T) {
 			)
 
 			require.NoError(t, err)
+
+			elementType := interpreter.ConvertSemaToStaticType(
+				nil,
+				testCase.ty,
+			)
+			rangeType := interpreter.NewInclusiveRangeStaticType(nil, elementType)
+
+			var expectedRangeValue *interpreter.CompositeValue
+
+			if withStep {
+				expectedRangeValue = interpreter.NewInclusiveRangeValueWithStep(
+					inter,
+					interpreter.EmptyLocationRange,
+					interpreter.GetValueForIntegerType(testCase.s, elementType),
+					interpreter.GetValueForIntegerType(testCase.e, elementType),
+					interpreter.GetValueForIntegerType(testCase.step, elementType),
+					rangeType,
+				)
+			} else {
+				expectedRangeValue = interpreter.NewInclusiveRangeValue(
+					inter,
+					interpreter.EmptyLocationRange,
+					interpreter.GetValueForIntegerType(testCase.s, elementType),
+					interpreter.GetValueForIntegerType(testCase.e, elementType),
+					rangeType,
+				)
+			}
+
+			utils.AssertValuesEqual(
+				t,
+				inter,
+				expectedRangeValue,
+				inter.Globals.Get("r").GetValue(),
+			)
+
+			// Check that contains returns correct information.
+			for i, tc := range testCase.containsTests {
+				var expectedValue interpreter.Value
+				if withStep {
+					expectedValue = interpreter.AsBoolValue(tc.expectedWithStep)
+				} else {
+					expectedValue = interpreter.AsBoolValue(tc.expectedWithoutStep)
+				}
+
+				utils.AssertValuesEqual(
+					t,
+					inter,
+					expectedValue,
+					inter.Globals.Get(fmt.Sprintf("c_%d", i)).GetValue(),
+				)
+			}
 		})
 	}
 
-	runValidCaseWithoutStep := func(t *testing.T, memberType sema.Type) {
-		runValidCase(t, memberType, false)
+	// Run each test case with and without step.
+	for _, testCase := range validTestCases {
+		runValidCase(t, testCase, true)
+		runValidCase(t, testCase, false)
 	}
-	runValidCaseWithStep := func(t *testing.T, memberType sema.Type) {
-		runValidCase(t, memberType, true)
+}
+
+func TestInclusiveRangeConstructionInvalid(t *testing.T) {
+	t.Parallel()
+
+	baseValueActivation := sema.NewVariableActivation(sema.BaseValueActivation)
+	baseValueActivation.DeclareValue(stdlib.InclusiveRangeConstructorFunction)
+
+	baseActivation := activations.NewActivation(nil, interpreter.BaseActivation)
+	interpreter.Declare(baseActivation, stdlib.InclusiveRangeConstructorFunction)
+
+	runInvalidCase := func(t *testing.T, label, code string, expectedError error, expectedMessage string) {
+		t.Run(label, func(t *testing.T) {
+			t.Parallel()
+
+			_, err := parseCheckAndInterpretWithOptions(t, code,
+				ParseCheckAndInterpretOptions{
+					CheckerConfig: &sema.Config{
+						BaseValueActivation: baseValueActivation,
+					},
+					Config: &interpreter.Config{
+						BaseActivation: baseActivation,
+					},
+				},
+			)
+
+			RequireError(t, err)
+
+			require.ErrorAs(t, err, expectedError)
+			require.True(t, strings.Contains(err.Error(), expectedMessage))
+		})
 	}
 
 	for _, integerType := range sema.AllIntegerTypes {
+		// Only test leaf types
 		switch integerType {
 		case sema.IntegerType, sema.SignedIntegerType:
 			continue
 		}
 
-		runValidCaseWithStep(t, integerType)
-		runValidCaseWithoutStep(t, integerType)
+		typeString := integerType.String()
+
+		// step = 0.
+		runInvalidCase(
+			t,
+			typeString,
+			fmt.Sprintf("let r = InclusiveRange(%s(1), %s(2), step: %s(0))", typeString, typeString, typeString),
+			&interpreter.InclusiveRangeConstructionError{},
+			"step value cannot be zero",
+		)
+
+		// step takes sequence away from end.
+		runInvalidCase(
+			t,
+			typeString,
+			fmt.Sprintf("let r = InclusiveRange(%s(40), %s(2), step: %s(2))", typeString, typeString, typeString),
+			&interpreter.InclusiveRangeConstructionError{},
+			"sequence is moving away from end",
+		)
+	}
+
+	// Additional invalid cases for signed integer types
+	for _, integerType := range sema.AllSignedIntegerTypes {
+		// Only test leaf types
+		switch integerType {
+		case sema.SignedIntegerType:
+			continue
+		}
+
+		typeString := integerType.String()
+
+		// step takes sequence away from end with step being negative.
+		// This would be a checker error for unsigned integers but a
+		// runtime error in signed integers.
+		runInvalidCase(
+			t,
+			typeString,
+			fmt.Sprintf("let r = InclusiveRange(%s(4), %s(100), step: %s(-2))", typeString, typeString, typeString),
+			&interpreter.InclusiveRangeConstructionError{},
+			"sequence is moving away from end",
+		)
+	}
+
+	// Additional invalid cases for unsigned integer types
+	for _, integerType := range sema.AllUnsignedIntegerTypes {
+		// Only test leaf types
+		switch integerType {
+		case sema.IntegerType:
+			continue
+		}
+
+		typeString := integerType.String()
+
+		runInvalidCase(
+			t,
+			typeString,
+			fmt.Sprintf("let r = InclusiveRange(%s(40), %s(1))", typeString, typeString),
+			&interpreter.InclusiveRangeConstructionError{},
+			"step value cannot be negative for unsigned integer type",
+		)
 	}
 }