The 31-year-old joined Dortmund from Bayer Leverkusen for €11m in 2015 and made a positive impact in his first season, scoring three goals in 25 Bundesliga appearances as the club finished second, 10 points behind Bayern Munich.
Since then, Castro's performances have dwindled and he started only 16 of the club's league matches as they finished fourth in 2017-18, and he joins Stuttgart on the back of their successful seventh-placed finish on their first season back in the Bundesliga.
A message on Dortmund's official Twitter account read: "Thanks for everything, 'Gonzo'!
"Our number 27 leaves the BVB after three years and moves to VfB Stuttgart.
"We wish you all the best!"
Danke für alles, "Gonzo"! Unsere Nummer 27 verlässt nach drei Jahren den BVB und wechselt zum @VfB Stuttgart.
Wir wünschen Dir alles Gute! pic.twitter.com/qByFefJ2ui — Borussia Dortmund (@BVB) June 29, 2018
Meanwhile, Stuttgart have allowed striker Daniel Ginczek to move to Wolfsburg on a four-year deal.
The 27-year-old target man, who began his career at Dortmund and enjoyed his most prolific spell at St. Pauli, scored seven goals in 17 starts in the Bundesliga in 2017-18.
A new striker in Green-White! VfB Stuttgart striker Daniel #Ginczek is on his way to #VfLWolfsburg, with the 27-year-old having signed a deal until 2022. #vflwolfsburg pic.twitter.com/zmD1Ac3MOR — VfL Wolfsburg EN (@VfLWolfsburg_EN) June 29, 2018