In a large skillet over medium-low heat, melt 2 tablespoons butter. Add sliced onions and cook, stirring frequently, until they are deeply golden and caramelized, about 30-45 minutes. Set aside.
Preheat the oven to 400°F. Lightly spray an 8×8-inch casserole dish with nonstick cooking spray. Set aside.
In a medium saucepan over medium heat, melt the remaining 2 tablespoons butter. Whisk in flour and kosher salt, and cook, whisking constantly, for 1 minute to form a roux.
Slowly whisk in the milk, making sure there are no lumps. Continue to cook, whisking frequently, until the sauce thickens and begins to bubble, about 5-7 minutes.
Remove from heat and stir in ½ cup shredded cheddar and ½ cup Gruyère, reserving the remaining ¼ cup of each for topping. Stir until smooth.
Arrange all of the potato slices in an even, overlapping layer in the prepared casserole dish. Pour the cheese sauce evenly over the potatoes, gently tilting the dish or using a spatula to help it seep between layers.
Spread the caramelized onions evenly over the cheesy potatoes. Then, sprinkle the remaining ¼ cup of cheddar and ¼ cup Gruyère on top.
Cover the dish tightly with aluminum foil and bake for 85-90 minutes, or until the potatoes are tender when pierced with a fork. Remove the foil for the last 10 minutes of baking to allow the top to brown. For an extra golden, crisp top, broil for 2-4 minutes, watching closely to prevent burning.
Let cool for 5-10 minutes before serving. Salt to taste and garnish with parsley.